[
  {
    "path": ".asf.yaml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nnotifications:\n  commits: notifications@shardingsphere.apache.org\n  issues: notifications@shardingsphere.apache.org\n  pullrequests: notifications@shardingsphere.apache.org\n\ngithub:\n  description: Distributed scheduled job\n  labels:\n    - elasticjob\n    - database\n    - scheduled-jobs\n    - cron\n    - job\n    - job-management\n    - shard\n    - quartz\n    - middleware\n  features:\n    issues: true\n    projects: true\n  protected_branches:\n    master:\n      required_status_checks:\n        contexts:\n          - Check - CheckStyle\n          - Check - Spotless\n          - Check - License\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.md",
    "content": "---\nname: \"\\U0001F41B Bug Report\"\nabout: Something isn't working as expected\n---\n\n## Bug Report\n\n**For English only**, other languages will not accept.\n\nBefore report a bug, make sure you have:\n\n- Searched open and closed [GitHub issues](https://github.com/apache/shardingsphere-elasticjob/issues).\n- Read documentation: [ElasticJob Doc](https://shardingsphere.apache.org/elasticjob/current/en/overview/).\n\nPlease pay attention on issues you submitted, because we maybe need more details. \nIf no response anymore and we cannot reproduce it on current information, we will **close it**.\n\nPlease answer these questions before submitting your issue. Thanks!\n\n### Which version of ElasticJob did you use?\n\n### Expected behavior\n\n### Actual behavior\n\n### Reason analyze (If you can)\n\n### Steps to reproduce the behavior.\n\n### Example codes for reproduce this issue (such as a github link).\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.md",
    "content": "---\nname: \"\\U0001F680 Feature Request\"\nabout: I have a suggestion\n---\n\n## Feature Request\n\n**For English only**, other languages will not accept.\n\nPlease pay attention on issues you submitted, because we maybe need more details. \nIf no response anymore and we cannot make decision by current information, we will **close it**.\n\nPlease answer these questions before submitting your issue. Thanks!\n\n### Is your feature request related to a problem?\n\n### Describe the feature you would like.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "content": "---\nname: \"\\U0001F914 Question\"\nabout: Usage question that isn't answered in docs or discussion\n---\n\n## Question\n\n**For English only**, other languages will not accept.\n\nBefore asking a question, make sure you have:\n\n- Googled your question.\n- Searched open and closed [GitHub issues](https://github.com/apache/shardingsphere-elasticjob/issues).\n- Read documentation: [ElasticJob Doc](https://shardingsphere.apache.org/elasticjob/current/en/overview/).\n\nPlease pay attention on issues you submitted, because we maybe need more details. \nIf no response anymore and we cannot reproduce it on current information, we will **close it**.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE",
    "content": "Fixes #ISSUSE_ID.\n\nChanges proposed in this pull request:\n-\n-\n-\n"
  },
  {
    "path": ".github/workflows/graalvm.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nname: NativeTest CI - GraalVM Native Image\n\non:\n  pull_request:\n    branches: [ master ]\n    paths:\n      - '.github/workflows/graalvm.yml'\n      - 'reachability-metadata/src/**'\n      - 'test/native/**'\n\njobs:\n  build:\n    if: github.repository == 'apache/shardingsphere-elasticjob'\n    strategy:\n      matrix:\n        java: [ '22.0.2' ]\n        os: [ 'ubuntu-latest' ]\n    runs-on: ${{ matrix.os }}\n    steps:\n      - uses: actions/checkout@v4\n      - name: Set up GraalVM CE ${{ matrix.java }}\n        uses: graalvm/setup-graalvm@v1\n        with:\n          java-version: ${{ matrix.java }}\n          distribution: 'graalvm-community'\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          cache: 'maven'\n          native-image-job-reports: 'true'\n      - name: Run nativeTest with GraalVM CE for ${{ matrix.java }}\n        run: ./mvnw -PnativeTestInElasticJob -T1C -B -e clean test\n"
  },
  {
    "path": ".github/workflows/maven.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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# This workflow will build a Java project with Maven\n# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven\n\nname: Java CI with Maven\n\non:\n  pull_request:\n    branches: [ master ]\n\njobs:\n  build:\n    if: github.repository == 'apache/shardingsphere-elasticjob'\n    strategy:\n      matrix:\n        java: [ 8, 17, 21, 24 ]\n        os: [ 'windows-latest', 'macos-latest', 'ubuntu-latest' ]\n    runs-on: ${{ matrix.os }}\n    steps:\n      - name: Configure Git\n        if: matrix.os == 'windows-latest'\n        run: |\n          git config --global core.longpaths true\n      - uses: actions/checkout@v4\n      - name: Set up JDK ${{ matrix.java }}\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: ${{ matrix.java }}\n          cache: 'maven'\n      - name: Build with Maven in Windows\n        if: matrix.os == 'windows-latest'\n        run: |\n          ./mvnw --batch-mode --no-transfer-progress '-Dmaven.javadoc.skip=true' clean install -T1C\n      - name: Build with Maven in Linux or macOS\n        if: matrix.os == 'macos-latest' || matrix.os == 'ubuntu-latest'\n        run: |\n          ./mvnw --batch-mode --no-transfer-progress '-Dmaven.javadoc.skip=true' clean install -Pcheck -T1C\n      - name: Upload coverage to Codecov\n        if: matrix.os == 'ubuntu-latest' && matrix.java == '8'\n        uses: codecov/codecov-action@v3\n        with:\n          file: '**/target/site/jacoco/jacoco.xml'\n      - name: Build Examples with Maven\n        run: ./mvnw clean package -B -f examples/pom.xml -T1C\n"
  },
  {
    "path": ".github/workflows/required-check.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nname: Required - Check\n\non:\n  pull_request:\n    branches: [ master ]\n  workflow_dispatch:\n\nconcurrency:\n  group: check-${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\njobs:\n  check-checkstyle:\n    name: Check - CheckStyle\n    if: github.repository == 'apache/shardingsphere-elasticjob'\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@v3\n      - name: Run CheckStyle\n        run: ./mvnw checkstyle:check -Pcheck -T1C\n\n  check-spotless:\n    name: Check - Spotless\n    if: github.repository == 'apache/shardingsphere-elasticjob'\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@v3\n      - name: Run Spotless\n        run: ./mvnw spotless:check -Pcheck -T1C\n\n  check-license:\n    name: Check - License\n    if: github.repository == 'apache/shardingsphere-elasticjob'\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - uses: actions/checkout@v3\n      - name: Run Apache Rat\n        run: ./mvnw apache-rat:check -Pcheck -T1C\n"
  },
  {
    "path": ".gitignore",
    "content": "# maven ignore\r\ntarget/\r\n*.class\r\n*.jar\r\n*.war\r\n*.zip\r\n*.tar\r\n*.tar.gz\r\ndependency-reduced-pom.xml\r\n.flattened-pom.xml\r\npom.xml.versionsBackup\r\n\r\n# maven plugin ignore\r\nrelease.properties\r\n*.gpg\r\n\r\n# eclipse ignore\r\n.settings/\r\n.project\r\n.classpath\r\n.factorypath\r\n\r\n# idea ignore\r\n.idea/\r\n!/.idea/icon.png\r\n!/.idea/vcs.xml\r\n*.ipr\r\n*.iml\r\n*.iws\r\n\r\n# vscode ignore\r\n.vscode/\r\n\r\n# temp ignore\r\nlogs/\r\n*.log\r\n*.tlog\r\n*.doc\r\n*.cache\r\n*.diff\r\n*.patch\r\n*.tmp\r\n\r\n# system ignore\r\n.DS_Store\r\nThumbs.db\r\n\r\n# antlr ignore\r\ngen/\r\n*.tokens\r\n\r\n# profiler ignore\r\n.profiler/\r\n\r\n# hugo ignore\r\npublic/\r\n.hugo_build.lock\r\n*.html-e\r\n"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"IssueNavigationConfiguration\">\n    <option name=\"links\">\n      <list>\n        <IssueNavigationLink>\n          <option name=\"issueRegexp\" value=\"#(\\d+)\" />\n          <option name=\"linkRegexp\" value=\"https://github.com/apache/shardingsphere-elasticjob/pull/$1\" />\n        </IssueNavigationLink>\n      </list>\n    </option>\n  </component>\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"\" vcs=\"Git\" />\n  </component>\n</project>\n"
  },
  {
    "path": ".mvn/jvm.config",
    "content": "-Xmx1024m -XX:MaxMetaspaceSize=256m\n"
  },
  {
    "path": ".mvn/wrapper/maven-wrapper.properties",
    "content": "wrapperVersion=3.3.4\ndistributionType=only-script\ndistributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 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\n=======================================================================\nApache ShardingSphere Subcomponents:\n\nThe Apache ShardingSphere project contains subcomponents with separate copyright\nnotices and license terms. Your use of the source code for the these\nsubcomponents is subject to the terms and conditions of the following\nlicenses.\n\n========================================================================\nApache 2.0 licenses\n========================================================================\n\nThe following components are provided under the Apache License. See project link for details.\nThe text of each license is the standard Apache 2.0 license.\n\n    Maven Wrapper(mvnw, mvnw.cmd files in root path), https://github.com/apache/maven-wrapper, Apache 2.0\n"
  },
  {
    "path": "NOTICE",
    "content": "Apache ShardingSphere\nCopyright 2018-2026 The Apache Software Foundation\n\nThis product includes software developed at\nThe Apache Software Foundation (http://www.apache.org/).\n"
  },
  {
    "path": "README.md",
    "content": "# [ElasticJob - Distributed scheduled job](http://shardingsphere.apache.org/elasticjob/)\n\n**Official website: https://shardingsphere.apache.org/elasticjob/**\n\n[![Stargazers over time](https://starchart.cc/apache/shardingsphere-elasticjob.svg)](https://starchart.cc/apache/shardingsphere-elasticjob)\n\nThrough the functions of flexible scheduling, resource management and job management, \nit creates a distributed scheduling solution suitable for Internet scenarios, \nand provides a diversified job ecosystem through open architecture design.\nIt uses a unified job API for each project.\nDevelopers only need code one time and can deploy at will.\n\nElasticJob became an [Apache ShardingSphere](https://shardingsphere.apache.org/) Sub-project on May 28 2020.\n\nYou are welcome to communicate with the community via the [mailing list](mailto:dev@shardingsphere.apache.org).\n\n[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)\n\n[![GitHub release](https://img.shields.io/github/release/apache/shardingsphere-elasticjob.svg)](https://github.com/apache/shardingsphere-elasticjob/releases)\n\n[![Maven Status](https://maven-badges.herokuapp.com/maven-central/org.apache.shardingsphere.elasticjob/elasticjob/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.apache.shardingsphere.elasticjob/elasticjob)\n[![Build Status](https://api.travis-ci.com/apache/shardingsphere-elasticjob.svg?branch=master)](https://travis-ci.org/apache/shardingsphere-elasticjob)\n[![GitHub Workflow](https://img.shields.io/github/actions/workflow/status/apache/shardingsphere-elasticjob/maven.yml?branch=master)](https://github.com/apache/shardingsphere-elasticjob/actions/workflows/maven.yml?query=branch%3Amaster)\n[![codecov](https://codecov.io/gh/apache/shardingsphere-elasticjob/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/shardingsphere-elasticjob)\n[![Maintainability](https://cloud.quality-gate.com/dashboard/api/badge?projectName=apache_shardingsphere-elasticjob&branchName=master)](https://cloud.quality-gate.com/dashboard/branches/396041#overview)\n\n## Introduction\n\nUsing ElasticJob developers can no longer worry about the non functional requirements such as job scale out, so that they can focus more on business coding.\nAt the same time, it can release operators too, so that they do not have to worry about high availability and management, and can automatically operate by simply adding servers.\n\nIt is a lightweight, decentralized solution that provides distributed task sharding services.\n\n![ElasticJob Architecture](https://shardingsphere.apache.org/elasticjob/current/img/architecture/elasticjob_lite.png)\n\n## Features\n\n- Elastic Schedule\n  - Support job sharding and high availability in distributed system\n  - Scale out for throughput and efficiency improvement\n  - Job processing capacity is flexible and scalable with the allocation of resources\n\n- Resource Assign\n  - Execute job on suitable time and assigned resources\n  - Aggregation same job to same job executor\n  - Append resources to newly assigned jobs dynamically\n\n- Job Governance\n  - Failover\n  - Misfired\n  - Self diagnose and recover when distribute environment unstable\n\n- Job Dependency (TODO)\n  - DAG based job dependency\n  - DAG based job item dependency\n\n- Job Open Ecosystem\n  - Unify job api for extension\n  - Support rich job type lib, such as dataflow, script, HTTP, file, big data\n  - Focus business SDK, can work with Spring IOC\n\n- [Admin Console](https://github.com/apache/shardingsphere-elasticjob-ui)\n  - Job administration\n  - Job event trace query\n  - Registry center management\n\n## Environment Required\n\n### Java\n\nJava 8 or above required.\n\n### Maven\n\nMaven 3.5.0 or above required.\n\n### ZooKeeper\n\nZooKeeper 3.6.0 or above required. [See details](https://zookeeper.apache.org/)\n"
  },
  {
    "path": "README_ZH.md",
    "content": "# [ElasticJob - 分布式作业调度解决方案](http://shardingsphere.apache.org/elasticjob/)\n\n**官方网站: https://shardingsphere.apache.org/elasticjob/**\n\n[![Stargazers over time](https://starchart.cc/apache/shardingsphere-elasticjob.svg)](https://starchart.cc/apache/shardingsphere-elasticjob)\n\nElasticJob 是面向互联网生态和海量任务的分布式调度解决方案。\n它通过弹性调度、资源管控、以及作业治理的功能，打造一个适用于互联网场景的分布式调度解决方案，并通过开放的架构设计，提供多元化的作业生态。\n它的各个产品使用统一的作业 API，开发者仅需一次开发，即可随意部署。\n\nElasticJob 已于 2020 年 5 月 28 日成为 [Apache ShardingSphere](https://shardingsphere.apache.org/) 的子项目。\n欢迎通过[邮件列表](mailto:dev@shardingsphere.apache.org)参与讨论。\n\n[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)\n\n[![GitHub release](https://img.shields.io/github/release/apache/shardingsphere-elasticjob.svg)](https://github.com/apache/shardingsphere-elasticjob/releases)\n\n[![Maven Status](https://maven-badges.herokuapp.com/maven-central/org.apache.shardingsphere.elasticjob/elasticjob/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.apache.shardingsphere.elasticjob/elasticjob)\n[![Build Status](https://secure.travis-ci.org/apache/shardingsphere-elasticjob.png?branch=master)](https://travis-ci.org/apache/shardingsphere-elasticjob)\n[![GitHub Workflow](https://img.shields.io/github/workflow/status/apache/shardingsphere-elasticjob/Java%20CI%20with%20Maven%20on%20macOS/master)](https://github.com/apache/shardingsphere-elasticjob/actions?query=workflow%3A%22Java+CI+with+Maven+on+macOS%22)\n[![codecov](https://codecov.io/gh/apache/shardingsphere-elasticjob/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/shardingsphere-elasticjob)\n\n## 简介\n\n使用 ElasticJob 能够让开发工程师不再担心任务的线性吞吐量提升等非功能需求，使他们能够更加专注于面向业务编码设计；\n同时，它也能够解放运维工程师，使他们不必再担心任务的可用性和相关管理需求，只通过轻松的增加服务节点即可达到自动化运维的目的。\n它定位为轻量级无中心化解决方案，使用 jar 的形式提供分布式任务的协调服务。\n\n![ElasticJob Architecture](https://shardingsphere.apache.org/elasticjob/current/img/architecture/elasticjob_lite.png)\n\n## 功能列表\n\n- 弹性调度\n  - 支持任务在分布式场景下的分片和高可用\n  - 能够水平扩展任务的吞吐量和执行效率\n  - 任务处理能力随资源配备弹性伸缩\n\n- 资源分配\n  - 在适合的时间将适合的资源分配给任务并使其生效\n  - 相同任务聚合至相同的执行器统一处理\n  - 动态调配追加资源至新分配的任务\n\n- 作业治理\n  - 失效转移\n  - 错过作业重新执行\n  - 自诊断修复\n\n- 作业依赖(TODO)\n  - 基于有向无环图（DAG）的作业间依赖\n  - 基于有向无环图（DAG）的作业分片间依赖\n\n- 作业开放生态\n  - 可扩展的作业类型统一接口\n  - 丰富的作业类型库，如数据流、脚本、HTTP、文件、大数据等\n  - 易于对接业务作业，能够与 Spring 依赖注入无缝整合\n\n- [可视化管控端](https://github.com/apache/shardingsphere-elasticjob-ui)\n  - 作业管控端\n  - 作业执行历史数据追踪\n  - 注册中心管理\n\n## 环境要求\n\n### Java\n\n请使用 Java 8 及其以上版本。\n\n### Maven\n\n请使用 Maven 3.5.0 及其以上版本。\n\n### ZooKeeper\n\n请使用 ZooKeeper 3.6.0 及其以上版本。[详情参见](https://zookeeper.apache.org/)\n"
  },
  {
    "path": "RELEASE-NOTES.md",
    "content": "## 3.0.5\n\n### CVE\n\n1. Fix CVE-2025-25193, CVE-2024-47535 [#2498](https://github.com/apache/shardingsphere-elasticjob/pull/2498)\n1. Fix CVE-2024-22259 [#2500](https://github.com/apache/shardingsphere-elasticjob/pull/2500)\n\n### API Changes\n\n1. Kernel: Refactor of the way Lambda job classes are identified - [#2370](https://github.com/apache/shardingsphere-elasticjob/issues/2370)\n\n### New Features\n\n1. Bootstrap: Provides built-in GraalVM Reachability Metadata and nativeTest on Elasticjob Bootstrap - [#2268](https://github.com/apache/shardingsphere-elasticjob/pull/2268)\n1. Lifecycle: Support dynamic configuration of jobs through the Operation API in GraalVM Native Image - [#2426](https://github.com/apache/shardingsphere-elasticjob/pull/2426)\n1. Registry Center: Allows to skip Ensemble Tracker for ZookeeperConfiguration to allow connecting to HA enabled Zookeeper clusters in Kubernetes - [#2072](https://github.com/apache/shardingsphere-elasticjob/issues/2072)\n\n### Enhancements\n\n1. Build: Support for building with OpenJDK 22 - [#2407](https://github.com/apache/shardingsphere-elasticjob/issues/2407)\n1. Spring Boot Starter: Block `elasticjob-spring-boot-starter` from passing `spring-boot-starter` test scope dependencies - [#2418](https://github.com/apache/shardingsphere-elasticjob/issues/2418)\n1. Doc: Adds documentation for connecting to Zookeeper Server with SASL enabled - [#2442](https://github.com/apache/shardingsphere-elasticjob/pull/2442)\n1. Dependencies: Bump Quartz to 2.4.0 - [#2439](https://github.com/apache/shardingsphere-elasticjob/issues/2439)\n1. Build: Support building and using ElasticJob with JDK23 - [#2453](https://github.com/apache/shardingsphere-elasticjob/issues/2453)\n1. Build: Support building and using ElasticJob with JDK24 - [#2481](https://github.com/apache/shardingsphere-elasticjob/pull/2481)\n\n### Bug Fixes\n\n1. Build: Removes non-existent `elasticjob-tracing-api` and `elasticjob-error-handler-spi` module - [#2412](https://github.com/apache/shardingsphere-elasticjob/pull/2412)\n1. Spring Boot Starter: Fixes the issue that OneOffJobBootstrap cannot be used under ElasticJob Spring Boot Starter - [#2014](https://github.com/apache/shardingsphere-elasticjob/issues/2014)\n1. Spring: Fixes potential conflict in AOP proxy job class identification in Spring Framework - [#2012](https://github.com/apache/shardingsphere-elasticjob/issues/2012)\n\n### Change Logs\n\n1. [MILESTONE](https://github.com/apache/shardingsphere-elasticjob/milestone/7)\n\n## 3.0.4\n\n### Dependencies Upgrade\n1. Update dependencies to fix CVE\n\n### Enhancements\n1. Support for building with OpenJDK 21\n2. Accelerate the startup speed of ElasticJob\n3. Migrate from Junit Vintage to Junit Jupiter\n\n### Change Logs\n\n1. [MILESTONE 3.0.4](https://github.com/apache/shardingsphere-elasticjob/milestone/9)\n\n\n## 3.0.3\n\n### Bug Fixes\n\n1. Job class conflict error caused by empty String\n1. Possible NPE in LegacyCrashedRunningItemListener\n1. Possible NPE in InstanceService.getAvailableJobInstances\n1. Job listeners configured in local configuration were used even if overwrite=false\n\n### Enhancements\n\n1. Add new job dump method in JobOperateAPI\n1. Avoid once listener invoke multi times\n\n### Change Logs\n\n1. [MILESTONE 3.0.3](https://github.com/apache/shardingsphere-elasticjob/milestone/8)\n\n\n## 3.0.2\n\n### Bug Fixes\n\n1. Fix itemErrorMessages not cleared after job finished.\n1. Fix Curator notify thread may be blocked and avoid probably endless loop in ServerService.\n1. NPE occur when job instance could not be unmarshalled.\n1. Fix failover too sensitive.\n\n### Enhancements\n\n1. Script Job exception's stack was ignored.\n1. Support using different event trace data source when using Spring Boot.\n1. Supports building project by Java 19.\n\n### Change Logs\n\n1. [MILESTONE 3.0.2](https://github.com/apache/shardingsphere-elasticjob/milestone/5)\n\n\n## 3.0.1\n\n### Enhancements\n\n1. Avoids creating too many threads for JobTracingEventBus\n1. Job listeners can be ordered\n1. Supports setting timezone for job\n1. Some enhancements in Spring Boot Starter\n1. Supports configuring preferred ip by regex\n\n### Bug Fixes\n\n1. Lifecycle module: JobOperateAPIImpl#trigger does not work\n1. Job conflict may occur when using Spring Boot Starter\n\n### Change Logs\n\n1. [MILESTONE 3.0.1](https://github.com/apache/shardingsphere-elasticjob/milestone/6)\n\n\n## 3.0.0\n\n### Enhancements\n\n1. Support configuring Mail SMTP SSL trust in elasticjob-error-handler-email\n\n### Bug Fixes\n\n1. The failover may not work in distributed deployment\n2. ReconcileService is still running after the job shutdown\n\n### Dependencies\n\n1. Make the spring-boot-starter-jdbc optional in ElasticJob Spring Boot Starter\n\n### Change Logs\n\n1. [MILESTONE 3.0.0](https://github.com/apache/shardingsphere-elasticjob/milestone/4)\n\n## 3.0.0-RC1\n\n### API Changes\n\n1. Simplify usage of injecting OneOffJob when using Spring Boot Starter\n1. Refactor job tracing configuration to support persistence\n\n### New Features\n\n1. Support reloading JobErrorHandler and ExecutorService when configuration changed\n1. Add authentication support in Cloud Scheduler\n\n### Bug Fixes\n\n1. Fix TracingConfiguration doesn't work when the property overwrite is false\n1. Fix SnapshotService may be unavailable in specific situation\n1. Fix some minor problems in Restful module\n\n### Build & Dependencies\n\n1. Upgrade commons-dbcp to commons-dbcp2 in Cloud Scheduler\n\n###  Change Logs\n\n1. [MILESTONE 3.0.0-RC1](https://github.com/apache/shardingsphere-elasticjob/milestone/3)\n\n## 3.0.0-beta\n\n### API Changes\n\n1. Refactor job listener configuration\n1. Refactor job error handler configuration\n1. Refactor job tracing configuration\n\n### New Features\n\n1. Support HTTP job\n1. Remove spring boot dependencies from job kernel module\n1. Support email notification when job execute error\n1. Support wechat notification when job execute error\n1. Support dingtalk notification when job execute error\n\n### Bug Fixes\n\n1. Fix bug of one-off job cannot work with sharding\n1. Fix bug of table and index name case-insensitive for event trace using database\n1. Fix bug of dead lock when resharding flag set incorrectly\n\n###  Change Logs\n\n1. [MILESTONE](https://github.com/apache/shardingsphere-elasticjob/milestone/2)\n\n## 3.0.0-alpha\n\n### Build & Dependencies\n\n1. Upgrade the minimum supported version of JDK to Java8\n1. Update Zookeeper to version 3.6.x and curator to version 5.1.0\n1. Update Google Guava to version 29.0-jre\n\n### API Changes\n\n1. Change maven groupId to org.apache.shardingsphere.elasticjob\n1. Change package name to org.apache.shardingsphere.elasticjob\n1. Change spring namespace name to http://shardingsphere.apache.org/schema/elasticjob\n1. New job API, use SPI to customize job type\n1. Use SPI to introduce configuration strategies\n1. Split console and UI from job core modules\n\n### New Features\n\n1. Add One-off job executor\n1. Add Spring Boot Starter for ElasticJob-Lite\n1. Add more databases support for event trace persist\n1. User indicate IP address via system environment supported\n\n### Bug Fixes\n\n1. Fix bug for executor thread ContextClassLoader is empty with ElasticJob-Cloud\n1. Fix bug for enable job from web console have no effect\n1. Shutdown job when application exit\n1. Fix NPE when failover out-of-order in Curator asynchronized persist\n1. Get correct job class name when using CGLIB proxy\n\n###  Change Logs\n\n1. [MILESTONE](https://github.com/apache/shardingsphere-elasticjob/milestone/1)\n\n## 2.1.5\n\n### New Features\n\n1. [ISSUE #373](https://github.com/elasticjob/elastic-job/issues/373) Cloud can distinguish processing TASK_UNREACHABLE,TASK_UNKNOWN,TASK_DROPPED,TASK_GONE,etc\n\n### Bug Fixes\n\n1. [ISSUE #367](https://github.com/elasticjob/elastic-job/issues/367) Massive stacked jobs performed after Cloud restart because disabled job does not stop Ready queue\n1. [ISSUE #382](https://github.com/elasticjob/elastic-job/issues/382) UI verification error, maximum number of shards should not be verified\n1. [ISSUE #383](https://github.com/elasticjob/elastic-job/issues/383) UI verification error, minimum number of listening port should not be verified\n\n## 2.1.4\n\n### Enhancement\n\n1. [ISSUE #29](https://github.com/elasticjob/elastic-job/issues/29)   Console support english\n1. [ISSUE #352](https://github.com/elasticjob/elastic-job/issues/352) Running elastic-job-cloud-executor locally without mesos environment\n\n### Bug Fixes\n\n1. [ISSUE #322](https://github.com/elasticjob/elastic-job/issues/322) Schedule tasks to evaluate resources when considering the use of resources for executor in elastic-job-cloud-scheduler module\n1. [ISSUE #341](https://github.com/elasticjob/elastic-job/issues/341) Script task configuration in elastic-job-cloud-console is missing execution script\n1. [ISSUE #343](https://github.com/elasticjob/elastic-job/issues/343) Script task execution script is incorrect in elastic-job-cloud-console module\n1. [ISSUE #345](https://github.com/elasticjob/elastic-job/issues/345) The status is not displayed correctly when the task is all disabled in elastic-job-lite-console module\n1. [ISSUE #351](https://github.com/elasticjob/elastic-job/issues/351) Manage background add registry, login credentials bar can not enter ':' in elastic-job-lite-console module\n\n## 2.1.3\n\n### Enhancement\n\n1. [ISSUE #327](https://github.com/elasticjob/elastic-job/issues/327) spring namespace supports use xml to config beans\n1. [ISSUE #336](https://github.com/elasticjob/elastic-job/issues/336) Cloud task submission failure returns error details to framework\n\n### Bug Fixes\n\n1. [ISSUE #321](https://github.com/elasticjob/elastic-job/issues/321) elastic-job-lite The namespace is not support / when UI adds the registry\n1. [ISSUE #333](https://github.com/elasticjob/elastic-job/issues/333) elastic-job-lite Registration center configuration login credentials in the UI implicit display\n1. [ISSUE #334](https://github.com/elasticjob/elastic-job/issues/334) elastic-job-lite UI can't find conf\\auth.properties file on windows platform\n1. [ISSUE #335](https://github.com/elasticjob/elastic-job/issues/335) elastic-job-lite UI guest account configuration does not work in conf\\auth.properties file\n\n## 2.1.2\n\n### New Features\n\n1. [ISSUE #301](https://github.com/elasticjob/elastic-job/issues/301) Console add guest permission configuration, guest only allows viewing, not allowed to change\n1. [ISSUE #312](https://github.com/elasticjob/elastic-job/issues/312) Cloud support self-healing\n\n### Enhancement\n\n1. [ISSUE #293](https://github.com/elasticjob/elastic-job/issues/293) Lite Console datasource configuration adds connection testing capabilities\n1. [ISSUE #296](https://github.com/elasticjob/elastic-job/issues/296) Cloud operational UI refactoring, consistent with lite style\n1. [ISSUE #302](https://github.com/elasticjob/elastic-job/issues/302) Failure transfer and task run state monitoring separation\n1. [ISSUE #304](https://github.com/elasticjob/elastic-job/issues/304) Cloud add associated features with Mesos roles\n1. [ISSUE #316](https://github.com/elasticjob/elastic-job/issues/316) Lite running task association process ID\n\n### Bug Fixes\n\n1. [ISSUE #291](https://github.com/elasticjob/elastic-job/issues/291) elastic-job console failure reason display is not complete\n1. [ISSUE #306](https://github.com/elasticjob/elastic-job/issues/306) Switch whether to monitor job execution status and task intervals are short may occur when the task cannot continue to run\n1. [ISSUE #310](https://github.com/elasticjob/elastic-job/issues/310) Create to many sequential nodes after configuration check time error seconds for this machine and registry\n\n## 2.1.1\n\n### New Features\n\n1. [ISSUE #242](https://github.com/elasticjob/elastic-job/issues/242) Elastic-Job-Cloud supports delete application and task\n1. [ISSUE #243](https://github.com/elasticjob/elastic-job/issues/243) Elastic-Job-Cloud supports enable/disable application and task\n\n### Enhancement\n\n1. [ISSUE #268](https://github.com/elasticjob/elastic-job/issues/268) Simplify POM dependency\n\n### Bug Fixes\n\n1. [ISSUE #266](https://github.com/elasticjob/elastic-job/issues/266) Elastic-Job-Lite start script specifies that the port is invalid\n1. [ISSUE #269](https://github.com/elasticjob/elastic-job/issues/269) EventTrace failure record is not affected by sample rate and the time of failure is recorded\n1. [ISSUE #270](https://github.com/elasticjob/elastic-job/issues/270) Console send two requests after clicks the button\n1. [ISSUE #272](https://github.com/elasticjob/elastic-job/issues/272) Elastic-Job-Lite UI job dimensions that should appear as disabled only if all servers are disabled\n1. [ISSUE #275](https://github.com/elasticjob/elastic-job/issues/275) After stopping Zookeeper, restart Zookeeper and the task does not continue\n1. [ISSUE #276](https://github.com/elasticjob/elastic-job/issues/276) When fail transfer is turned on and the shard task is performed, the task is repeated\n1. [ISSUE #279](https://github.com/elasticjob/elastic-job/issues/279) Add event tracking data source, database connection address can not have parameters\n1. [ISSUE #280](https://github.com/elasticjob/elastic-job/issues/280) The historical status of the task history page is not displayed correctly\n1. [ISSUE #283](https://github.com/elasticjob/elastic-job/issues/283) Task is not set overwrite and local configuration is inconsistent with the registration center, the cron started by the task shall be based on the registry\n1. [ISSUE #290](https://github.com/elasticjob/elastic-job/issues/290) Elastic-Job-Cloud when deleting a disabled APP or JOB, the corresponding disabled node data cannot be deleted\n\n## 2.1.0\n\n### New Features\n\n1. [ISSUE #195](https://github.com/elasticjob/elastic-job/issues/195) Elastic-Job-Lite self-diagnose and fix problems caused by distributed instability\n1. [ISSUE #248](https://github.com/elasticjob/elastic-job/issues/248) Elastic-Job-Lite the same job server can run multiple JVM instances with the same job name(Cloud Native)\n1. [ISSUE #249](https://github.com/elasticjob/elastic-job/issues/249) Elastic-Job-Lite Operations UI supports incident tracking queries\n\n### Enhancement\n\n1. [ISSUE #240](https://github.com/elasticjob/elastic-job/issues/240) Elastic-Job-Lite operational UI refactoring.\n1. [ISSUE #262](https://github.com/elasticjob/elastic-job/issues/262) Elastic-Job-Lite console delete job configuration.\n\n### Bug Fixes\n\n1. [ISSUE #237](https://github.com/elasticjob/elastic-job/issues/238) Add the REST API check on the total number of shards not less than 1\n1. [ISSUE #238](https://github.com/elasticjob/elastic-job/issues/238) IP regular expression error\n1. [ISSUE #246](https://github.com/elasticjob/elastic-job/issues/246) After using JobOperateAPI.remove()，JobScheduler.init() triggers execution multiple times after creating the same job\n1. [ISSUE #250](https://github.com/elasticjob/elastic-job/issues/250) Misfire task triggers more than once\n\n### Refactor\n\n1. [ISSUE #263](https://github.com/elasticjob/elastic-job/issues/263) Elastic-Job-Lite Job OperationAPI Re-grooming\n1. [ISSUE #264](https://github.com/elasticjob/elastic-job/issues/264) Elastic-Job-Lite Data storage restructuring, but forward compatibility\n\n## 2.0.5\n\n### New Features\n\n1. [ISSUE #191](https://github.com/elasticjob/elastic-job/issues/191) Framework's HA feature\n1. [ISSUE #217](https://github.com/elasticjob/elastic-job/issues/217) cloud add APP dimension configuration\n1. [ISSUE #223](https://github.com/elasticjob/elastic-job/issues/223) cloud resident job event tracking sample rate\n\n### Bug Fixes\n\n1. [ISSUE 222](https://github.com/elasticjob/elastic-job/issues/222) elastic-job-lite-spring reg configuration parameter max-retries does not work\n1. [ISSUE 231](https://github.com/elasticjob/elastic-job/issues/231) When a cloud job is deleted in bulk, mesos synchronizes TASK_LOST message to the framework in advance, causing the job to be re-arranged in the ready queue and executed\n\n## 2.0.4\n\n### New Features\n\n1. [ISSUE #203](https://github.com/elasticjob/elastic-job/issues/203) Cloud task add run statistics and provide REST API queries\n1. [ISSUE #215](https://github.com/elasticjob/elastic-job/issues/215) cloud operations management UI\n\n### Enhancement\n\n1. [ISSUE #187](https://github.com/elasticjob/elastic-job/issues/187) ShardingContext add task attribute to business side\n\n### Bug Fixes\n\n1. [ISSUE #189](https://github.com/elasticjob/elastic-job/issues/189) Manage background to perform a failure operation, but the task is still being executed\n1. [ISSUE #204](https://github.com/elasticjob/elastic-job/issues/204) Async execution of messages in consistency results in inaccurate database data\n1. [ISSUE #209](https://github.com/elasticjob/elastic-job/issues/209) cloud task resource allocation algorithm improvement\n\n## 2.0.3\n\n### Refactor\n\n1. [ISSUE #184](https://github.com/elasticjob/elastic-job/issues/184) ExecutorServiceHandler interface method adjustment, add jobName used to distinguish between different job thread names\n1. [ISSUE #186](https://github.com/elasticjob/elastic-job/issues/186) Simplify SpringJobScheduler use by removing Spring Namespace DTO-related code\n\n### New Features\n\n1. [ISSUE #178](https://github.com/elasticjob/elastic-job/issues/178) Event-driven trigger jobs\n\n### Enhancement\n\n1. [ISSUE #179](https://github.com/elasticjob/elastic-job/issues/179) Transient's Script-type task optimization, no Java Executor support required\n1. [ISSUE #182](https://github.com/elasticjob/elastic-job/issues/182) add support for spring boot\n\n### Bug Fixes\n\n1. [ISSUE #177](https://github.com/elasticjob/elastic-job/issues/177) Spring Namespace Job: Script Null Pointer in version 2.0.2\n1. [ISSUE #185](https://github.com/elasticjob/elastic-job/issues/185) Executor over-occupancy of sharding resources leads to waste of resources\n\n## 2.0.2\n\n### Refactor\n\n1. [ISSUE #153](https://github.com/elasticjob/elastic-job/issues/153) Centralization of event tracking configuration\n1. [ISSUE #160](https://github.com/elasticjob/elastic-job/issues/160) Adjust the maven module structure to provide elastic-job-common and its secondary modules, the original elastic-job-core module migration to elastic-job-common-core\n\n### Enhancement\n\n1. [ISSUE #159](https://github.com/elasticjob/elastic-job/issues/159) Available in any version from Spring 3.1.0.RELEASE to Spring 4\n1. [ISSUE #164](https://github.com/elasticjob/elastic-job/issues/164) JobBeans that have been declared in the job Spring namespace no longer need to declare @Component or define in Spring xml\n\n### Bug Fixes\n\n1. [ISSUE #64](https://github.com/elasticjob/elastic-job/issues/64)   Spring namespace, if you register multiple job beans of the same class, will cause job beans to look up inaccurately\n1. [ISSUE #115](https://github.com/elasticjob/elastic-job/issues/115) Console add new registry, no connection success, back stage has been repeatedly connected and reported errors\n1. [ISSUE #151](https://github.com/elasticjob/elastic-job/issues/151) Lack of support for relational database-based event tracking for databases outside MySQL\n1. [ISSUE #152](https://github.com/elasticjob/elastic-job/issues/152) Job custom exception processor is invalid and is always handled by Default JobExceptionHandler\n1. [ISSUE #156](https://github.com/elasticjob/elastic-job/issues/156) Job event tracking overall call link data acquisition\n1. [ISSUE #158](https://github.com/elasticjob/elastic-job/issues/158) Job misses sharding when it is paused and will no longer shard\n1. [ISSUE #161](https://github.com/elasticjob/elastic-job/issues/161) Version of Lite deployed to some versions of Tomcat cannot be started\n1. [ISSUE #163](https://github.com/elasticjob/elastic-job/issues/163) The project is started or the task is automatically performed after the task is set to disable true\n1. [ISSUE #165](https://github.com/elasticjob/elastic-job/issues/165) Shard thread deadlock when all service nodes are disable\n1. [ISSUE #167](https://github.com/elasticjob/elastic-job/issues/167) Failover job adds task ID record\n\n## 2.0.1\n\n### Bug Fixes\n\n1. [ISSUE #141](https://github.com/elasticjob/elastic-job/issues/141) Remove the reg module to read information from zk, making the reg namespace's placeholder fully available\n1. [ISSUE #143](https://github.com/elasticjob/elastic-job/issues/143) elastic-job-cloud-scheduler memory leak\n1. [ISSUE #145](https://github.com/elasticjob/elastic-job/issues/145) After modifying the database connection of the task log, the log is still written to the old database\n1. [ISSUE #146](https://github.com/elasticjob/elastic-job/issues/146) Thread pool reuse problem for a task\n1. [ISSUE #147](https://github.com/elasticjob/elastic-job/issues/147) console task does not load, background there is an null pointer exception\n1. [ISSUE #149](https://github.com/elasticjob/elastic-job/issues/149) Operations platform delete tasks, occasionally encounter deletion incomplete situation\n1. [ISSUE #150](https://github.com/elasticjob/elastic-job/issues/150) Cloud's misfire feature will be performed as jobs pile up\n\n## 2.0.0\n\n### New Features\n\n1. Elastic-Job-Cloud initial version\n1. Reconstruct the original Elastic-Job to Elastic-Job-Lite\n\n### Bug Fixes\n\n1. [ISSUE #119](https://github.com/elasticjob/elastic-job/issues/119) Quartz does not close properly when spring container is closed \n1. [ISSUE #123](https://github.com/elasticjob/elastic-job/issues/123) Stand-alone running timing task, zk disconnect after reconnecting, did not trigger the leader election\n1. [ISSUE #127](https://github.com/elasticjob/elastic-job/issues/127) Spring configuration task id cannot use placeholders\n\n## 1.1.1\n\n### Refactor\n\n1. [ISSUE #116](https://github.com/elasticjob/elastic-job/issues/116) HandleJobExecutionException parameter changes for job interface\n\n### Enhancement\n\n1. [ISSUE #110](https://github.com/elasticjob/elastic-job/issues/110) Trigger the task manually\n\n### Bug Fixes\n\n1. [ISSUE #99](https://github.com/elasticjob/elastic-job/issues/99) After deleting a task asynchronously caused the job to be deleted, the task that has not yet ended continues to create zk data\n\n## 1.1.0\n\n### Refactor\n\n1. [ISSUE #97](https://github.com/elasticjob/elastic-job/issues/97)   JobConfiguration Refactored to SimpleJobConfiguration，DataflowJobConfiguration，ScriptJobConfiguration\n1. [ISSUE #102](https://github.com/elasticjob/elastic-job/issues/102) Redefine Java/Spring Config API，replace Constructor+Setter with Factory+Builder model\n1. [ISSUE #104](https://github.com/elasticjob/elastic-job/issues/104) Remove @Deprecated code\n1. [ISSUE #105](https://github.com/elasticjob/elastic-job/issues/105) Reconstructing the Spring Namespace Hump Definition\n1. [ISSUE #106](https://github.com/elasticjob/elastic-job/issues/106) isStreaming Configuration\n1. [ISSUE #107](https://github.com/elasticjob/elastic-job/issues/107) reg-center renamed registry-center-ref\n\n## 1.0.8\n\n### New Features\n\n1. [ISSUE #95](https://github.com/elasticjob/elastic-job/issues/95) Add script type job support\n\n## 1.0.7\n\n### Refactor\n\n1. [ISSUE #88](https://github.com/elasticjob/elastic-job/issues/88) Stop task renamed pause\n\n### New Features\n\n1. [ISSUE #91](https://github.com/elasticjob/elastic-job/issues/91) Job Lifecycle Action API\n\n### Enhancement\n\n1. [ISSUE #84](https://github.com/elasticjob/elastic-job/issues/84) The console provides job enable/disable button action\n1. [ISSUE #87](https://github.com/elasticjob/elastic-job/issues/87) Adjusting the master node election process, job shutdown, disabling and pausing will trigger the master node election\n1. [ISSUE #93](https://github.com/elasticjob/elastic-job/issues/93) The registry configuration provides default values for baseSleepTimeMilliseconds, maxSleepTimeMilliseconds, and maxRetries\n\n### Bug Fixes\n\n1. [ISSUE #92](https://github.com/elasticjob/elastic-job/issues/92) Modifying the total shard parameter results in a listening throw timeout exception performed by only a single node\n\n## 1.0.6\n\n### Enhancement\n\n1. [ISSUE #71](https://github.com/elasticjob/elastic-job/issues/71) Task off function（shutdown）\n1. [ISSUE #72](https://github.com/elasticjob/elastic-job/issues/72) Closed jobs can be deleted\n1. [ISSUE #81](https://github.com/elasticjob/elastic-job/issues/81) Using the last end state of a centralized cleanup job instead of the respective cleanup, each cleaning may result in an uncleaned end state due to offline\n\n### Bug Fixes\n\n1. [ISSUE #74](https://github.com/elasticjob/elastic-job/issues/74) When streaming and fail transfer, the failover shard item cannot be executed once and stopped\n1. [ISSUE #77](https://github.com/elasticjob/elastic-job/issues/77) Dataflow type task, fetchData if there is data, should be executed in pairs with processData\n1. [ISSUE #78](https://github.com/elasticjob/elastic-job/issues/78) Spring configuration job monitoring enable AOP causes problems that do not work properly\n\n## 1.0.5\n\n### Refactor\n\n1. [ISSUE #59](https://github.com/elasticjob/elastic-job/issues/59) elastic-job upgrade curator from 2.8.0 to 2.10.0\n\n### Enhancement\n\n1. [ISSUE #2](https://github.com/elasticjob/elastic-job/issues/2)   Add front and post tasks\n1. [ISSUE #60](https://github.com/elasticjob/elastic-job/issues/60) Dataflow type task customized thread pool configuration\n1. [ISSUE #62](https://github.com/elasticjob/elastic-job/issues/61) Job status cleanup speed-up\n1. [ISSUE #65](https://github.com/elasticjob/elastic-job/issues/65) Add spring namespace support for front and post tasks\n\n### Bug Fixes\n\n1. [ISSUE #61](https://github.com/elasticjob/elastic-job/issues/61) Deadlock problem solved when sharding and primary node elections occur at the same time\n1. [ISSUE #63](https://github.com/elasticjob/elastic-job/issues/63) You may get TreeCache for other jobs with the same prefix when you get the job TreeCache\n1. [ISSUE #69](https://github.com/elasticjob/elastic-job/issues/69) If the job server sharding node in Zk does not exist when sharding, it will not be able to reshard\n\n## 1.0.4\n\n### Refactor\n\n1. [ISSUE #57](https://github.com/elasticjob/elastic-job/issues/57) Thin module, remove elastic-job-test module\n1. [ISSUE #58](https://github.com/elasticjob/elastic-job/issues/58) Add changes in job type interfaces due to bulk processing capabilities\n\n### Enhancement\n\n1. [ISSUE #16](https://github.com/elasticjob/elastic-job/issues/16) Provides embedded zookeeper to simplify the development environment\n1. [ISSUE #28](https://github.com/elasticjob/elastic-job/issues/28) Dataflow type tasks to increase processData bulk processing of data\n1. [ISSUE #56](https://github.com/elasticjob/elastic-job/issues/56) Job custom parameter settings\n\n## 1.0.3\n\n### Enhancement\n\n1. [ISSUE #39](https://github.com/elasticjob/elastic-job/issues/39) Add job assisted listening and fetch job runtime information with dump command\n1. [ISSUE #43](https://github.com/elasticjob/elastic-job/issues/43) Add job exception handling callback interface\n\n### Bug Fixes\n\n1. [ISSUE #30](https://github.com/elasticjob/elastic-job/issues/30) Registry is down for a long time and resumes, and the job cannot continue\n1. [ISSUE #36](https://github.com/elasticjob/elastic-job/issues/36) Task cannot resume after console pause\n1. [ISSUE #40](https://github.com/elasticjob/elastic-job/issues/40) TreeCache uses Coarse granularity cause memory overflow\n\n## 1.0.2\n\n### Refactor\n\n1. [ISSUE #17](https://github.com/elasticjob/elastic-job/issues/17) Task type interface changes\n\n### Enhancement\n\n1. [ISSUE #6](https://github.com/elasticjob/elastic-job/issues/6)   Proofreading job server and registry time error\n1. [ISSUE #8](https://github.com/elasticjob/elastic-job/issues/8)   Increase misfire switch, default enable missed task re-execution\n1. [ISSUE #9](https://github.com/elasticjob/elastic-job/issues/9)   Sharding policy configurability\n1. [ISSUE #10](https://github.com/elasticjob/elastic-job/issues/10) Provides a sorting strategy for odd even shards based on job name hash value\n1. [ISSUE #14](https://github.com/elasticjob/elastic-job/issues/14) When the console modifies the cron expression, the task updates the cron in real time\n1. [ISSUE #20](https://github.com/elasticjob/elastic-job/issues/20) Operations UI task list shows increased cron expression\n1. [ISSUE #54](https://github.com/elasticjob/elastic-job/issues/54) Sequenceperpetual task performance improved, changing fetch data to multithreaded, previously processing data only as multithreaded\n1. [ISSUE #55](https://github.com/elasticjob/elastic-job/issues/55) offset storage capabilities\n\n### Bug Fixes\n\n1. [ISSUE #1](https://github.com/elasticjob/elastic-job/issues/1)   Inaccurate access to IP addresses in complex network environments\n1. [ISSUE #13](https://github.com/elasticjob/elastic-job/issues/13) After a job throws a run-time exception, it does not continue to be triggered later\n1. [ISSUE #53](https://github.com/elasticjob/elastic-job/issues/53) Dataflow's Sequence type tasks use multithreaded fetch data\n\n## 1.0.1\n\n1. Initial version\n"
  },
  {
    "path": "api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-api</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere</groupId>\n            <artifactId>shardingsphere-infra-spi</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/annotation/ElasticJobConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.annotation;\n\nimport org.apache.shardingsphere.elasticjob.api.JobExtraConfigurationFactory;\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 * The annotation that specify a job of elastic.\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\npublic @interface ElasticJobConfiguration {\n    \n    /**\n     * Job name.\n     * \n     * @return job name\n     */\n    String jobName();\n    \n    /**\n     * CRON expression, control the job trigger time.\n     * \n     * @return cron\n     */\n    String cron() default \"\";\n    \n    /**\n     * Time zone of CRON.\n     * \n     * @return time zone\n     */\n    String timeZone() default \"\";\n    \n    /**\n     * Registry center name.\n     * \n     * @return registry center\n     */\n    String registryCenter() default \"\";\n    \n    /**\n     * Sharding total count.\n     * \n     * @return sharding total count\n     */\n    int shardingTotalCount();\n    \n    /**\n     * Sharding item parameters.\n     * \n     * @return sharding item parameters\n     */\n    String shardingItemParameters() default \"\";\n    \n    /**\n     * Job parameter.\n     * \n     * @return job parameter\n     */\n    String jobParameter() default \"\";\n    \n    /**\n     * Monitor job execution status.\n     * \n     * @return monitor execution\n     */\n    boolean monitorExecution() default true;\n    \n    /**\n     * Enable or disable job failover.\n     * \n     * @return failover\n     */\n    boolean failover() default false;\n    \n    /**\n     * Enable or disable the missed task to re-execute.\n     * \n     * @return misfire\n     */\n    boolean misfire() default true;\n    \n    /**\n     * The maximum value for time difference between server and registry center in seconds.\n     * \n     * @return max time diff seconds\n     */\n    int maxTimeDiffSeconds() default -1;\n    \n    /**\n     * Service scheduling interval in minutes for repairing job server inconsistent state.\n     * \n     * @return reconcile interval minutes\n     */\n    int reconcileIntervalMinutes() default 10;\n    \n    /**\n     * Job sharding strategy type.\n     * \n     * @return job sharding strategy type\n     */\n    String jobShardingStrategyType() default \"\";\n    \n    /**\n     * Job executor thread pool size provider type.\n     * \n     * @return job executor thread pool size provider type\n     */\n    String jobExecutorThreadPoolSizeProviderType() default \"\";\n    \n    /**\n     * Job thread pool handler type.\n     * \n     * @return job error handler type\n     */\n    String jobErrorHandlerType() default \"\";\n    \n    /**\n     * Job listener types.\n     * \n     * @return job listener types\n     */\n    String[] jobListenerTypes() default {};\n    \n    /**\n     * Extra configurations.\n     * \n     * @return extra configurations\n     */\n    Class<? extends JobExtraConfigurationFactory>[] extraConfigurations() default {};\n    \n    /**\n     * Job description.\n     * \n     * @return description\n     */\n    String description() default \"\";\n    \n    /**\n     * Job properties.\n     * \n     * @return properties\n     */\n    ElasticJobProp[] props() default {};\n    \n    /**\n     * Enable or disable start the job.\n     * \n     * @return disabled\n     */\n    boolean disabled() default false;\n    \n    /**\n     * Enable or disable local configuration override registry center configuration.\n     * \n     * @return overwrite\n     */\n    boolean overwrite() default false;\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/annotation/ElasticJobProp.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * The annotation that specify elastic-job prop.\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ElasticJobProp {\n    \n    /**\n     * Prop key.\n     * \n     * @return key\n     */\n    String key();\n    \n    /**\n     * Prop value.\n     * \n     * @return value\n     */\n    String value() default \"\";\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/api/ElasticJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.api;\n\n/**\n * ElasticJob interface.\n */\npublic interface ElasticJob {\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/api/JobConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.api;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport lombok.AccessLevel;\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.LinkedList;\nimport java.util.Properties;\n\n/**\n * ElasticJob configuration.\n */\n@Getter\n@AllArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class JobConfiguration {\n    \n    private final String jobName;\n    \n    private final String cron;\n    \n    private final String timeZone;\n    \n    private final int shardingTotalCount;\n    \n    private final String shardingItemParameters;\n    \n    private final String jobParameter;\n    \n    private final boolean monitorExecution;\n    \n    private final boolean failover;\n    \n    private final boolean misfire;\n    \n    private final int maxTimeDiffSeconds;\n    \n    private final int reconcileIntervalMinutes;\n    \n    private final String jobShardingStrategyType;\n    \n    private final String jobExecutorThreadPoolSizeProviderType;\n    \n    private final String jobErrorHandlerType;\n    \n    private final Collection<String> jobListenerTypes;\n    \n    private final Collection<JobExtraConfiguration> extraConfigurations;\n    \n    private final String description;\n    \n    private final Properties props;\n    \n    private final boolean disabled;\n    \n    private final boolean overwrite;\n    \n    private final String label;\n    \n    private final boolean staticSharding;\n    \n    /**\n     * Create ElasticJob configuration builder.\n     *\n     * @param jobName job name\n     * @param shardingTotalCount sharding total count\n     * @return ElasticJob configuration builder\n     */\n    public static Builder newBuilder(final String jobName, final int shardingTotalCount) {\n        return new Builder(jobName, shardingTotalCount);\n    }\n    \n    @RequiredArgsConstructor(access = AccessLevel.PRIVATE)\n    public static class Builder {\n        \n        private final String jobName;\n        \n        private String cron;\n        \n        private String timeZone;\n        \n        private final int shardingTotalCount;\n        \n        private String shardingItemParameters = \"\";\n        \n        private String jobParameter = \"\";\n        \n        private boolean monitorExecution = true;\n        \n        private boolean failover;\n        \n        private boolean misfire = true;\n        \n        private int maxTimeDiffSeconds = -1;\n        \n        private int reconcileIntervalMinutes = 10;\n        \n        private String jobShardingStrategyType;\n        \n        private String jobExecutorThreadPoolSizeProviderType;\n        \n        private String jobErrorHandlerType;\n        \n        private final Collection<String> jobListenerTypes = new ArrayList<>();\n        \n        private final Collection<JobExtraConfiguration> extraConfigurations = new LinkedList<>();\n        \n        private String description = \"\";\n        \n        private final Properties props = new Properties();\n        \n        private boolean disabled;\n        \n        private boolean overwrite;\n        \n        private String label;\n        \n        private boolean staticSharding;\n        \n        /**\n         * Cron expression.\n         *\n         * @param cron cron expression\n         * @return job configuration builder\n         */\n        public Builder cron(final String cron) {\n            if (null != cron) {\n                this.cron = cron;\n            }\n            return this;\n        }\n        \n        /**\n         * time zone.\n         *\n         * @param timeZone the time zone\n         * @return job configuration builder\n         */\n        public Builder timeZone(final String timeZone) {\n            if (null != timeZone) {\n                this.timeZone = timeZone;\n            }\n            return this;\n        }\n        \n        /**\n         * Set mapper of sharding items and sharding parameters.\n         *\n         * <p>\n         * sharding item and sharding parameter split by =, multiple sharding items and sharding parameters split by comma, just like map.\n         * Sharding item start from zero, cannot equal to great than sharding total count.\n         * For example:\n         * 0=a,1=b,2=c\n         * </p>\n         *\n         * @param shardingItemParameters mapper of sharding items and sharding parameters\n         * @return job configuration builder\n         */\n        public Builder shardingItemParameters(final String shardingItemParameters) {\n            if (null != shardingItemParameters) {\n                this.shardingItemParameters = shardingItemParameters;\n            }\n            return this;\n        }\n        \n        /**\n         * Set job parameter.\n         *\n         * @param jobParameter job parameter\n         *\n         * @return job configuration builder\n         */\n        public Builder jobParameter(final String jobParameter) {\n            if (null != jobParameter) {\n                this.jobParameter = jobParameter;\n            }\n            return this;\n        }\n        \n        /**\n         * Set enable or disable monitor execution.\n         *\n         * <p>\n         * For short interval job, it is better to disable monitor execution to improve performance. \n         * It can't guarantee repeated data fetch and can't failover if disable monitor execution, please keep idempotence in job.\n         * For long interval job, it is better to enable monitor execution to guarantee fetch data exactly once.\n         * </p>\n         *\n         * @param monitorExecution monitor job execution status \n         * @return ElasticJob configuration builder\n         */\n        public Builder monitorExecution(final boolean monitorExecution) {\n            this.monitorExecution = monitorExecution;\n            return this;\n        }\n        \n        /**\n         * Set enable failover.\n         *\n         * <p>\n         * Only for `monitorExecution` enabled.\n         * </p> \n         *\n         * @param failover enable or disable failover\n         * @return job configuration builder\n         */\n        public Builder failover(final boolean failover) {\n            this.failover = failover;\n            return this;\n        }\n        \n        /**\n         * Set enable misfire.\n         *\n         * @param misfire enable or disable misfire\n         * @return job configuration builder\n         */\n        public Builder misfire(final boolean misfire) {\n            this.misfire = misfire;\n            return this;\n        }\n        \n        /**\n         * Set max tolerate time different seconds between job server and registry center.\n         *\n         * <p>\n         * ElasticJob will throw exception if exceed max tolerate time different seconds.\n         * -1 means do not check.\n         * </p>\n         *\n         * @param maxTimeDiffSeconds max tolerate time different seconds between job server and registry center\n         * @return ElasticJob configuration builder\n         */\n        public Builder maxTimeDiffSeconds(final int maxTimeDiffSeconds) {\n            this.maxTimeDiffSeconds = maxTimeDiffSeconds;\n            return this;\n        }\n        \n        /**\n         * Set reconcile interval minutes for job sharding status.\n         *\n         * <p>\n         * Monitor the status of the job server at regular intervals, and resharding if incorrect.\n         * </p>\n         *\n         * @param reconcileIntervalMinutes reconcile interval minutes for job sharding status\n         * @return ElasticJob configuration builder\n         */\n        public Builder reconcileIntervalMinutes(final int reconcileIntervalMinutes) {\n            this.reconcileIntervalMinutes = reconcileIntervalMinutes;\n            return this;\n        }\n        \n        /**\n         * Set job sharding strategy type.\n         *\n         * <p>\n         * Default for {@code AverageAllocationJobShardingStrategy}.\n         * </p>\n         *\n         * @param jobShardingStrategyType job sharding strategy type\n         * @return ElasticJob configuration builder\n         */\n        public Builder jobShardingStrategyType(final String jobShardingStrategyType) {\n            if (null != jobShardingStrategyType) {\n                this.jobShardingStrategyType = jobShardingStrategyType;\n            }\n            return this;\n        }\n        \n        /**\n         * Set job executor thread pool size provider type.\n         *\n         * @param jobExecutorThreadPoolSizeProviderType job executor thread pool size provider type\n         * @return job configuration builder\n         */\n        public Builder jobExecutorThreadPoolSizeProviderType(final String jobExecutorThreadPoolSizeProviderType) {\n            this.jobExecutorThreadPoolSizeProviderType = jobExecutorThreadPoolSizeProviderType;\n            return this;\n        }\n        \n        /**\n         * Set job error handler type.\n         *\n         * @param jobErrorHandlerType job error handler type\n         * @return job configuration builder\n         */\n        public Builder jobErrorHandlerType(final String jobErrorHandlerType) {\n            this.jobErrorHandlerType = jobErrorHandlerType;\n            return this;\n        }\n        \n        /**\n         * Set job listener types.\n         *\n         * @param jobListenerTypes job listener types\n         * @return ElasticJob configuration builder\n         */\n        public Builder jobListenerTypes(final String... jobListenerTypes) {\n            this.jobListenerTypes.addAll(Arrays.asList(jobListenerTypes));\n            return this;\n        }\n        \n        /**\n         * Add extra configurations.\n         *\n         * @param extraConfig job extra configuration\n         * @return job configuration builder\n         */\n        public Builder addExtraConfigurations(final JobExtraConfiguration extraConfig) {\n            extraConfigurations.add(extraConfig);\n            return this;\n        }\n        \n        /**\n         * Set job description.\n         *\n         * @param description job description\n         * @return job configuration builder\n         */\n        public Builder description(final String description) {\n            if (null != description) {\n                this.description = description;\n            }\n            return this;\n        }\n        \n        /**\n         * Set property.\n         *\n         * @param key property key\n         * @param value property value\n         * @return job configuration builder\n         */\n        public Builder setProperty(final String key, final String value) {\n            props.setProperty(key, value);\n            return this;\n        }\n        \n        /**\n         * Set whether disable job when start.\n         * \n         * <p>\n         * Using in job deploy, start job together after deploy.\n         * </p>\n         *\n         * @param disabled whether disable job when start\n         * @return ElasticJob configuration builder\n         */\n        public Builder disabled(final boolean disabled) {\n            this.disabled = disabled;\n            return this;\n        }\n        \n        /**\n         * Set whether overwrite local configuration to registry center when job startup. \n         * \n         * <p>\n         *  If overwrite enabled, every startup will use local configuration.\n         * </p>\n         *\n         * @param overwrite whether overwrite local configuration to registry center when job startup\n         * @return ElasticJob configuration builder\n         */\n        public Builder overwrite(final boolean overwrite) {\n            this.overwrite = overwrite;\n            return this;\n        }\n        \n        /**\n         * Set label.\n         *\n         * @param label label\n         * @return ElasticJob configuration builder\n         */\n        public Builder label(final String label) {\n            this.label = label;\n            return this;\n        }\n        \n        /**\n         * Set static sharding.\n         *\n         * @param staticSharding static sharding\n         * @return ElasticJob configuration builder\n         */\n        public Builder staticSharding(final boolean staticSharding) {\n            this.staticSharding = staticSharding;\n            return this;\n        }\n        \n        /**\n         * Build ElasticJob configuration.\n         * \n         * @return ElasticJob configuration\n         */\n        public final JobConfiguration build() {\n            Preconditions.checkArgument(!Strings.isNullOrEmpty(jobName), \"jobName can not be empty.\");\n            Preconditions.checkArgument(shardingTotalCount > 0, \"shardingTotalCount should larger than zero.\");\n            return new JobConfiguration(jobName, cron, timeZone, shardingTotalCount, shardingItemParameters, jobParameter,\n                    monitorExecution, failover, misfire, maxTimeDiffSeconds, reconcileIntervalMinutes,\n                    jobShardingStrategyType, jobExecutorThreadPoolSizeProviderType, jobErrorHandlerType, jobListenerTypes,\n                    extraConfigurations, description, props, disabled, overwrite, label, staticSharding);\n        }\n    }\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/api/JobExtraConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.api;\n\n/**\n * Job extra configuration.\n */\npublic interface JobExtraConfiguration {\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/api/JobExtraConfigurationFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.api;\n\nimport java.util.Optional;\n\n/**\n * Job extra configuration factory.\n */\npublic interface JobExtraConfigurationFactory {\n    \n    /**\n     * Get job extra configuration.\n     * \n     * @return job extra configuration\n     */\n    Optional<JobExtraConfiguration> getJobExtraConfiguration();\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/executor/ExecutionType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.executor;\n\n/**\n * Execution type.\n */\npublic enum ExecutionType {\n    \n    /**\n     * Ready of execute.\n     */\n    READY,\n    \n    /**\n     * Failover execution.\n     */\n    FAILOVER\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/executor/error/handler/JobErrorHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.executor.error.handler;\n\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;\n\nimport java.io.Closeable;\n\n/**\n * Job error handler.\n */\npublic interface JobErrorHandler extends TypedSPI, Closeable {\n    \n    /**\n     * Handle exception.\n     * \n     * @param jobName job name\n     * @param cause failure cause\n     */\n    void handleException(String jobName, Throwable cause);\n    \n    @Override\n    String getType();\n    \n    @Override\n    default void close() {\n    }\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/executor/error/handler/JobErrorHandlerPropertiesValidator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.executor.error.handler;\n\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;\n\nimport java.util.Properties;\n\n/**\n * Job error handler properties validator.\n */\n@SingletonSPI\npublic interface JobErrorHandlerPropertiesValidator extends TypedSPI {\n    \n    /**\n     * Validate job properties.\n     *\n     * @param props job properties\n     */\n    void validate(Properties props);\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/executor/item/JobItemExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.executor.item;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\n\n/**\n * Job item executor.\n * \n * @param <T> type of ElasticJob\n */\npublic interface JobItemExecutor<T extends ElasticJob> {\n    \n    /**\n     * Process job item.\n     * \n     * @param elasticJob elastic job\n     * @param jobConfig job configuration\n     * @param jobRuntimeService job runtime service\n     * @param shardingContext sharding context\n     */\n    void process(T elasticJob, JobConfiguration jobConfig, JobRuntimeService jobRuntimeService, ShardingContext shardingContext);\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/executor/item/param/JobRuntimeService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.executor.item.param;\n\n/**\n * Job runtime service.\n */\npublic interface JobRuntimeService {\n    \n    /**\n     * Judge job whether to need resharding.\n     *\n     * @return need resharding or not\n     */\n    boolean isNeedSharding();\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/executor/item/param/ShardingContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.executor.item.param;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.ToString;\n\n/**\n * Sharding context.\n */\n@RequiredArgsConstructor\n@Getter\n@ToString\npublic final class ShardingContext {\n    \n    private final String jobName;\n    \n    private final String taskId;\n    \n    private final int shardingTotalCount;\n    \n    private final String jobParameter;\n    \n    private final int shardingItem;\n    \n    private final String shardingParameter;\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/executor/item/type/ClassedJobItemExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.executor.item.type;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.JobItemExecutor;\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\n\n/**\n * Classed job item executor.\n * \n * @param <T> type of ElasticJob\n */\n@SingletonSPI\npublic interface ClassedJobItemExecutor<T extends ElasticJob> extends JobItemExecutor<T> {\n    \n    /**\n     * Get elastic job class.\n     * \n     * @return elastic job class\n     */\n    Class<T> getElasticJobClass();\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/executor/item/type/TypedJobItemExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.executor.item.type;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.JobItemExecutor;\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;\n\n/**\n * Typed job item executor.\n */\n@SingletonSPI\npublic interface TypedJobItemExecutor extends JobItemExecutor<ElasticJob>, TypedSPI {\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/listener/ElasticJobListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;\n\n/**\n * ElasticJob listener.\n */\npublic interface ElasticJobListener extends TypedSPI {\n    \n    int LOWEST = Integer.MAX_VALUE;\n    \n    /**\n     * Called before job executed.\n     * \n     * @param shardingContexts sharding contexts\n     */\n    void beforeJobExecuted(ShardingContexts shardingContexts);\n    \n    /**\n     * Called after job executed.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    void afterJobExecuted(ShardingContexts shardingContexts);\n    \n    /**\n     * Listener order, default is the lowest.\n     * @return order\n     */\n    default int order() {\n        return LOWEST;\n    }\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/listener/param/ShardingContexts.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.listener.param;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.Setter;\nimport lombok.ToString;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\nimport java.io.Serializable;\nimport java.util.Map;\n\n/**\n * Sharding contexts.\n */\n@RequiredArgsConstructor\n@Getter\n@ToString\npublic final class ShardingContexts implements Serializable {\n    \n    private static final long serialVersionUID = -4585977349142082152L;\n    \n    private final String taskId;\n    \n    private final String jobName;\n    \n    private final int shardingTotalCount;\n    \n    private final String jobParameter;\n    \n    private final Map<Integer, String> shardingItemParameters;\n    \n    private int jobEventSamplingCount;\n    \n    @Setter\n    private int currentJobEventSamplingCount;\n    \n    @Setter\n    private boolean allowSendJobEvent = true;\n    \n    public ShardingContexts(final String taskId, final String jobName, final int shardingTotalCount, final String jobParameter,\n                            final Map<Integer, String> shardingItemParameters, final int jobEventSamplingCount) {\n        this.taskId = taskId;\n        this.jobName = jobName;\n        this.shardingTotalCount = shardingTotalCount;\n        this.jobParameter = jobParameter;\n        this.shardingItemParameters = shardingItemParameters;\n        this.jobEventSamplingCount = jobEventSamplingCount;\n    }\n    \n    /**\n     * Create sharding context.\n     * \n     * @param shardingItem sharding item\n     * @return sharding context\n     */\n    public ShardingContext createShardingContext(final int shardingItem) {\n        return new ShardingContext(jobName, taskId, shardingTotalCount, jobParameter, shardingItem, shardingItemParameters.get(shardingItem));\n    }\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/tracing/event/JobEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.tracing.event;\n\n/**\n * Job event.\n */\npublic interface JobEvent {\n    \n    /**\n     * Get job name.\n     * \n     * @return job name\n     */\n    String getJobName();\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/tracing/event/JobExecutionEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.tracing.event;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.Setter;\n\nimport java.util.Date;\nimport java.util.UUID;\n\n/**\n * Job execution event.\n */\n@AllArgsConstructor\n@RequiredArgsConstructor\n@Getter\npublic final class JobExecutionEvent implements JobEvent {\n    \n    private String id = UUID.randomUUID().toString();\n    \n    private final String hostname;\n    \n    private final String ip;\n    \n    private final String taskId;\n    \n    private final String jobName;\n    \n    private final ExecutionSource source;\n    \n    private final int shardingItem;\n    \n    private Date startTime = new Date();\n    \n    @Setter\n    private Date completeTime;\n    \n    @Setter\n    private boolean success;\n    \n    @Setter\n    private String failureCause;\n    \n    /**\n     * Execution success.\n     * \n     * @return job execution event\n     */\n    public JobExecutionEvent executionSuccess() {\n        JobExecutionEvent result = new JobExecutionEvent(id, hostname, ip, taskId, jobName, source, shardingItem, startTime, completeTime, success, failureCause);\n        result.setCompleteTime(new Date());\n        result.setSuccess(true);\n        return result;\n    }\n    \n    /**\n     * Execution failure.\n     * \n     * @param failureCause failure cause\n     * @return job execution event\n     */\n    public JobExecutionEvent executionFailure(final String failureCause) {\n        JobExecutionEvent result = new JobExecutionEvent(id, hostname, ip, taskId, jobName, source, shardingItem, startTime, completeTime, success, failureCause);\n        result.setCompleteTime(new Date());\n        result.setSuccess(false);\n        result.setFailureCause(failureCause);\n        return result;\n    }\n    \n    /**\n     * Execution source.\n     */\n    public enum ExecutionSource {\n        \n        NORMAL_TRIGGER, MISFIRE, FAILOVER\n    }\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/tracing/event/JobStatusTraceEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.tracing.event;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.spi.executor.ExecutionType;\n\nimport java.util.Date;\nimport java.util.UUID;\n\n/**\n * Job status trace event.\n */\n@AllArgsConstructor\n@RequiredArgsConstructor\n@Getter\npublic final class JobStatusTraceEvent implements JobEvent {\n    \n    private String id = UUID.randomUUID().toString();\n    \n    private final String jobName;\n    \n    @Setter\n    private String originalTaskId = \"\";\n    \n    private final String taskId;\n    \n    private final String slaveId;\n    \n    private final ExecutionType executionType;\n    \n    private final String shardingItems;\n    \n    private final State state;\n    \n    private final String message;\n    \n    private Date creationTime = new Date();\n    \n    public enum State {\n        TASK_STAGING, TASK_RUNNING, TASK_FINISHED, TASK_KILLED, TASK_LOST, TASK_FAILED, TASK_ERROR, TASK_DROPPED, TASK_GONE, TASK_GONE_BY_OPERATOR, TASK_UNREACHABLE, TASK_UNKNOWN\n    }\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/tracing/exception/TracingConfigurationException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.tracing.exception;\n\n/**\n * Tracing configuration exception.\n */\npublic final class TracingConfigurationException extends Exception {\n    \n    private static final long serialVersionUID = 4069519372148227761L;\n    \n    public TracingConfigurationException(final Exception ex) {\n        super(ex);\n    }\n    \n    public TracingConfigurationException(final String errorMessage) {\n        super(errorMessage);\n    }\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/tracing/listener/TracingListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.tracing.listener;\n\nimport com.google.common.eventbus.AllowConcurrentEvents;\nimport com.google.common.eventbus.Subscribe;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent;\n\n/**\n * Tracing listener.\n */\npublic interface TracingListener {\n    \n    /**\n     * Listen job execution event.\n     *\n     * @param jobExecutionEvent job execution event\n     */\n    @Subscribe\n    @AllowConcurrentEvents\n    void listen(JobExecutionEvent jobExecutionEvent);\n    \n    /**\n     * Listen job status trace event.\n     *\n     * @param jobStatusTraceEvent job status trace event\n     */\n    @Subscribe\n    @AllowConcurrentEvents\n    void listen(JobStatusTraceEvent jobStatusTraceEvent);\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/tracing/listener/TracingListenerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.tracing.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.tracing.exception.TracingConfigurationException;\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;\n\n/**\n * Tracing listener factory.\n * \n * @param <T> type of tracing storage\n */\n@SingletonSPI\npublic interface TracingListenerFactory<T> extends TypedSPI {\n    \n    /**\n     * Create tracing listener.\n     * \n     * @param storage storage\n     * @return tracing listener\n     * @throws TracingConfigurationException tracing configuration exception\n     */\n    TracingListener create(T storage) throws TracingConfigurationException;\n    \n    @Override\n    String getType();\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/tracing/storage/TracingStorageConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.tracing.storage;\n\n/**\n * Tracing storage configuration.\n *\n * @param <T> storage type\n */\npublic interface TracingStorageConfiguration<T> {\n    \n    /**\n     * Create storage.\n     *\n     * @return storage\n     */\n    T getStorage();\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/tracing/storage/TracingStorageConfigurationConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.tracing.storage;\n\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\n\n/**\n * Tracing storage configuration converter.\n *\n * @param <T> storage type\n */\n@SingletonSPI\npublic interface TracingStorageConfigurationConverter<T> {\n    \n    /**\n     * Convert storage to {@link TracingStorageConfiguration}.\n     *\n     * @param storage storage instance\n     * @return instance of {@link TracingStorageConfiguration}\n     */\n    TracingStorageConfiguration<T> toConfiguration(T storage);\n    \n    /**\n     * Storage type.\n     *\n     * @return class of storage\n     */\n    Class<T> storageType();\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/yaml/YamlConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.yaml;\n\nimport java.io.Serializable;\n\n/**\n * YAML configuration.\n *\n * @param <T> type of configuration\n */\npublic interface YamlConfiguration<T> extends Serializable {\n    \n    /**\n     * Convert to original configuration.\n     *\n     * @return configuration\n     */\n    T toConfiguration();\n}\n"
  },
  {
    "path": "api/src/main/java/org/apache/shardingsphere/elasticjob/spi/yaml/YamlConfigurationConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.yaml;\n\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;\n\n/**\n * YAML configuration converter.\n *\n * @param <T> type of original configuration object\n * @param <Y> type of YAML configuration\n */\n@SingletonSPI\npublic interface YamlConfigurationConverter<T, Y extends YamlConfiguration<T>> extends TypedSPI {\n    \n    /**\n     * Convert to YAML configuration.\n     *\n     * @param data data to be converted\n     * @return YAML configuration\n     */\n    Y convertToYamlConfiguration(T data);\n    \n    @Override\n    Class<T> getType();\n}\n"
  },
  {
    "path": "api/src/test/java/org/apache/shardingsphere/elasticjob/annotation/ElasticJobConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.annotation;\n\nimport org.apache.shardingsphere.elasticjob.annotation.job.impl.SimpleTestJob;\nimport org.apache.shardingsphere.elasticjob.api.JobExtraConfigurationFactory;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Arrays;\nimport java.util.LinkedList;\nimport java.util.Queue;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertArrayEquals;\n\nclass ElasticJobConfigurationTest {\n    \n    @Test\n    void assertAnnotationJob() {\n        ElasticJobConfiguration annotation = SimpleTestJob.class.getAnnotation(ElasticJobConfiguration.class);\n        assertThat(annotation.jobName(), is(\"SimpleTestJob\"));\n        assertThat(annotation.cron(), is(\"0/5 * * * * ?\"));\n        assertThat(annotation.shardingTotalCount(), is(3));\n        assertThat(annotation.shardingItemParameters(), is(\"0=Beijing,1=Shanghai,2=Guangzhou\"));\n        for (Class<? extends JobExtraConfigurationFactory> factory : annotation.extraConfigurations()) {\n            assertThat(factory, is(SimpleTracingConfigurationFactory.class));\n        }\n        assertArrayEquals(annotation.jobListenerTypes(), new String[]{\"NOOP\", \"LOG\"});\n        Queue<String> propsKey = new LinkedList<>(Arrays.asList(\"print.title\", \"print.content\"));\n        Queue<String> propsValue = new LinkedList<>(Arrays.asList(\"test title\", \"test content\"));\n        for (ElasticJobProp prop : annotation.props()) {\n            assertThat(prop.key(), is(propsKey.poll()));\n            assertThat(prop.value(), is(propsValue.poll()));\n        }\n    }\n}\n"
  },
  {
    "path": "api/src/test/java/org/apache/shardingsphere/elasticjob/annotation/SimpleTracingConfigurationFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.annotation;\n\nimport java.util.Optional;\nimport org.apache.shardingsphere.elasticjob.api.JobExtraConfiguration;\nimport org.apache.shardingsphere.elasticjob.api.JobExtraConfigurationFactory;\n\npublic final class SimpleTracingConfigurationFactory implements JobExtraConfigurationFactory {\n    \n    @Override\n    public Optional<JobExtraConfiguration> getJobExtraConfiguration() {\n        return Optional.empty();\n    }\n}\n"
  },
  {
    "path": "api/src/test/java/org/apache/shardingsphere/elasticjob/annotation/job/CustomJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.annotation.job;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\npublic interface CustomJob extends ElasticJob {\n    \n    /**\n     * Execute custom job.\n     *\n     * @param shardingContext sharding context\n     */\n    void execute(ShardingContext shardingContext);\n}\n"
  },
  {
    "path": "api/src/test/java/org/apache/shardingsphere/elasticjob/annotation/job/impl/SimpleTestJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.annotation.job.impl;\n\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobConfiguration;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobProp;\nimport org.apache.shardingsphere.elasticjob.annotation.SimpleTracingConfigurationFactory;\nimport org.apache.shardingsphere.elasticjob.annotation.job.CustomJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\n@ElasticJobConfiguration(\n        cron = \"0/5 * * * * ?\",\n        jobName = \"SimpleTestJob\",\n        shardingTotalCount = 3,\n        shardingItemParameters = \"0=Beijing,1=Shanghai,2=Guangzhou\",\n        jobListenerTypes = {\"NOOP\", \"LOG\"},\n        extraConfigurations = SimpleTracingConfigurationFactory.class,\n        props = {\n                @ElasticJobProp(key = \"print.title\", value = \"test title\"),\n                @ElasticJobProp(key = \"print.content\", value = \"test content\")\n        })\npublic final class SimpleTestJob implements CustomJob {\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n    }\n}\n"
  },
  {
    "path": "api/src/test/java/org/apache/shardingsphere/elasticjob/api/JobConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.api;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\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\nclass JobConfigurationTest {\n    \n    @Test\n    void assertBuildAllProperties() {\n        JobConfiguration actual = JobConfiguration.newBuilder(\"test_job\", 3)\n                .cron(\"0/1 * * * * ?\")\n                .timeZone(\"GMT+8\")\n                .shardingItemParameters(\"0=a,1=b,2=c\").jobParameter(\"param\")\n                .monitorExecution(false).failover(true).misfire(false)\n                .maxTimeDiffSeconds(1000).reconcileIntervalMinutes(60)\n                .jobShardingStrategyType(\"AVG_ALLOCATION\").jobExecutorThreadPoolSizeProviderType(\"SINGLE_THREAD\").jobErrorHandlerType(\"IGNORE\")\n                .description(\"desc\").setProperty(\"key\", \"value\")\n                .disabled(true).overwrite(true).build();\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getCron(), is(\"0/1 * * * * ?\"));\n        assertThat(actual.getTimeZone(), is(\"GMT+8\"));\n        assertThat(actual.getShardingTotalCount(), is(3));\n        assertThat(actual.getShardingItemParameters(), is(\"0=a,1=b,2=c\"));\n        assertThat(actual.getJobParameter(), is(\"param\"));\n        assertFalse(actual.isMonitorExecution());\n        assertTrue(actual.isFailover());\n        assertFalse(actual.isMisfire());\n        assertThat(actual.getMaxTimeDiffSeconds(), is(1000));\n        assertThat(actual.getReconcileIntervalMinutes(), is(60));\n        assertThat(actual.getJobShardingStrategyType(), is(\"AVG_ALLOCATION\"));\n        assertThat(actual.getJobExecutorThreadPoolSizeProviderType(), is(\"SINGLE_THREAD\"));\n        assertThat(actual.getJobErrorHandlerType(), is(\"IGNORE\"));\n        assertThat(actual.getDescription(), is(\"desc\"));\n        assertThat(actual.getProps().getProperty(\"key\"), is(\"value\"));\n        assertTrue(actual.isDisabled());\n        assertTrue(actual.isOverwrite());\n    }\n    \n    @Test\n    public void assertBuildRequiredProperties() {\n        JobConfiguration actual = JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").timeZone(\"GMT+8\").build();\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getCron(), is(\"0/1 * * * * ?\"));\n        assertThat(actual.getTimeZone(), is(\"GMT+8\"));\n        assertThat(actual.getShardingTotalCount(), is(3));\n        assertThat(actual.getShardingItemParameters(), is(\"\"));\n        assertThat(actual.getJobParameter(), is(\"\"));\n        assertTrue(actual.isMonitorExecution());\n        assertFalse(actual.isFailover());\n        assertTrue(actual.isMisfire());\n        assertThat(actual.getMaxTimeDiffSeconds(), is(-1));\n        assertThat(actual.getReconcileIntervalMinutes(), is(10));\n        assertNull(actual.getJobShardingStrategyType());\n        assertNull(actual.getJobExecutorThreadPoolSizeProviderType());\n        assertNull(actual.getJobErrorHandlerType());\n        assertThat(actual.getDescription(), is(\"\"));\n        assertTrue(actual.getProps().isEmpty());\n        assertFalse(actual.isDisabled());\n        assertFalse(actual.isOverwrite());\n    }\n    \n    @Test\n    void assertBuildWithEmptyJobName() {\n        assertThrows(IllegalArgumentException.class, () -> JobConfiguration.newBuilder(\"\", 3).cron(\"0/1 * * * * ?\").build());\n    }\n    \n    @Test\n    void assertBuildWithInvalidShardingTotalCount() {\n        assertThrows(IllegalArgumentException.class, () -> JobConfiguration.newBuilder(\"test_job\", -1).cron(\"0/1 * * * * ?\").build());\n    }\n}\n"
  },
  {
    "path": "api/src/test/java/org/apache/shardingsphere/elasticjob/spi/listener/param/ShardingContextsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spi.listener.param;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass ShardingContextsTest {\n    \n    @Test\n    void assertCreateShardingContext() {\n        ShardingContexts shardingContexts = createShardingContexts();\n        ShardingContext actual = shardingContexts.createShardingContext(1);\n        assertThat(actual.getJobName(), is(shardingContexts.getJobName()));\n        assertThat(actual.getTaskId(), is(shardingContexts.getTaskId()));\n        assertThat(actual.getShardingTotalCount(), is(shardingContexts.getShardingTotalCount()));\n        assertThat(actual.getJobParameter(), is(shardingContexts.getJobParameter()));\n        assertThat(actual.getShardingItem(), is(1));\n        assertThat(actual.getShardingParameter(), is(shardingContexts.getShardingItemParameters().get(1)));\n    }\n    \n    private ShardingContexts createShardingContexts() {\n        Map<Integer, String> map = new HashMap<>(2, 1F);\n        map.put(0, \"A\");\n        map.put(1, \"B\");\n        return new ShardingContexts(\"fake_task_id\", \"test_job\", 2, \"\", map);\n    }\n}\n"
  },
  {
    "path": "bootstrap/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-bootstrap</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-simple-executor</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-dataflow-executor</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-script-executor</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-http-executor</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-normal</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-tracing-rdb</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-reachability-metadata</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-test-util</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.awaitility</groupId>\n            <artifactId>awaitility</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "bootstrap/src/main/java/org/apache/shardingsphere/elasticjob/bootstrap/JobBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.bootstrap;\n\n/**\n * Job bootstrap.\n */\npublic interface JobBootstrap {\n    \n    /**\n     * Shutdown job.\n     */\n    void shutdown();\n}\n"
  },
  {
    "path": "bootstrap/src/main/java/org/apache/shardingsphere/elasticjob/bootstrap/type/OneOffJobBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.bootstrap.type;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.JobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.annotation.JobAnnotationBuilder;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduler;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\n/**\n * One off job bootstrap.\n */\npublic class OneOffJobBootstrap implements JobBootstrap {\n    \n    private final JobScheduler jobScheduler;\n    \n    private final InstanceService instanceService;\n    \n    public OneOffJobBootstrap(final CoordinatorRegistryCenter regCenter, final ElasticJob elasticJob, final JobConfiguration jobConfig) {\n        Preconditions.checkArgument(Strings.isNullOrEmpty(jobConfig.getCron()), \"Cron should be empty.\");\n        jobScheduler = new JobScheduler(regCenter, elasticJob, jobConfig);\n        instanceService = new InstanceService(regCenter, jobConfig.getJobName());\n    }\n    \n    public OneOffJobBootstrap(final CoordinatorRegistryCenter regCenter, final String elasticJobType, final JobConfiguration jobConfig) {\n        Preconditions.checkArgument(Strings.isNullOrEmpty(jobConfig.getCron()), \"Cron should be empty.\");\n        jobScheduler = new JobScheduler(regCenter, elasticJobType, jobConfig);\n        instanceService = new InstanceService(regCenter, jobConfig.getJobName());\n    }\n    \n    public OneOffJobBootstrap(final CoordinatorRegistryCenter regCenter, final ElasticJob elasticJob) {\n        JobConfiguration jobConfig = JobAnnotationBuilder.generateJobConfiguration(elasticJob.getClass());\n        jobScheduler = new JobScheduler(regCenter, elasticJob, jobConfig);\n        instanceService = new InstanceService(regCenter, jobConfig.getJobName());\n    }\n    \n    /**\n     * Execute job.\n     */\n    public void execute() {\n        instanceService.triggerAllInstances();\n    }\n    \n    @Override\n    public void shutdown() {\n        jobScheduler.shutdown();\n    }\n}\n"
  },
  {
    "path": "bootstrap/src/main/java/org/apache/shardingsphere/elasticjob/bootstrap/type/ScheduleJobBootstrap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.bootstrap.type;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.JobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.annotation.JobAnnotationBuilder;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduler;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\n/**\n * Schedule job bootstrap.\n */\npublic final class ScheduleJobBootstrap implements JobBootstrap {\n    \n    private final JobScheduler jobScheduler;\n    \n    public ScheduleJobBootstrap(final CoordinatorRegistryCenter regCenter, final ElasticJob elasticJob, final JobConfiguration jobConfig) {\n        jobScheduler = new JobScheduler(regCenter, elasticJob, jobConfig);\n    }\n    \n    public ScheduleJobBootstrap(final CoordinatorRegistryCenter regCenter, final String elasticJobType, final JobConfiguration jobConfig) {\n        jobScheduler = new JobScheduler(regCenter, elasticJobType, jobConfig);\n    }\n    \n    public ScheduleJobBootstrap(final CoordinatorRegistryCenter regCenter, final ElasticJob elasticJob) {\n        JobConfiguration jobConfig = JobAnnotationBuilder.generateJobConfiguration(elasticJob.getClass());\n        jobScheduler = new JobScheduler(regCenter, elasticJob, jobConfig);\n    }\n    \n    /**\n     * Schedule job.\n     */\n    public void schedule() {\n        Preconditions.checkArgument(!Strings.isNullOrEmpty(jobScheduler.getJobConfig().getCron()), \"Cron can not be empty.\");\n        jobScheduler.getJobScheduleController().scheduleJob(jobScheduler.getJobConfig().getCron(), jobScheduler.getJobConfig().getTimeZone());\n    }\n    \n    @Override\n    public void shutdown() {\n        jobScheduler.shutdown();\n    }\n}\n"
  },
  {
    "path": "bootstrap/src/test/java/org/apache/shardingsphere/elasticjob/bootstrap/type/OneOffJobBootstrapTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.bootstrap.type;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduler;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass OneOffJobBootstrapTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static final int SHARDING_TOTAL_COUNT = 3;\n    \n    private static ZookeeperRegistryCenter zkRegCenter;\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), OneOffJobBootstrapTest.class.getSimpleName());\n        zkRegCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        zkRegCenter.init();\n    }\n    \n    @AfterAll\n    static void tearDown() {\n        zkRegCenter.close();\n    }\n    \n    @Test\n    void assertConfigFailedWithCron() {\n        assertThrows(IllegalArgumentException.class, () -> new OneOffJobBootstrap(zkRegCenter, (SimpleJob) shardingContext -> {\n        }, JobConfiguration.newBuilder(\"test_one_off_job_execute_with_config_cron\", SHARDING_TOTAL_COUNT).cron(\"0/5 * * * * ?\").build()));\n    }\n    \n    @Test\n    void assertExecute() {\n        AtomicInteger counter = new AtomicInteger(0);\n        final OneOffJobBootstrap oneOffJobBootstrap = new OneOffJobBootstrap(zkRegCenter,\n                (SimpleJob) shardingContext -> counter.incrementAndGet(), JobConfiguration.newBuilder(\"test_one_off_job_execute\", SHARDING_TOTAL_COUNT).build());\n        oneOffJobBootstrap.execute();\n        blockUtilFinish(oneOffJobBootstrap, counter);\n        assertThat(counter.get(), is(SHARDING_TOTAL_COUNT));\n        ((JobScheduler) ReflectionUtils.getFieldValue(oneOffJobBootstrap, \"jobScheduler\")).shutdown();\n    }\n    \n    @Test\n    void assertShutdown() throws SchedulerException {\n        OneOffJobBootstrap oneOffJobBootstrap = new OneOffJobBootstrap(zkRegCenter, (SimpleJob) shardingContext -> {\n        }, JobConfiguration.newBuilder(\"test_one_off_job_shutdown\", SHARDING_TOTAL_COUNT).build());\n        oneOffJobBootstrap.shutdown();\n        assertTrue(getScheduler(oneOffJobBootstrap).isShutdown());\n    }\n    \n    private Scheduler getScheduler(final OneOffJobBootstrap oneOffJobBootstrap) {\n        JobScheduler jobScheduler = (JobScheduler) ReflectionUtils.getFieldValue(oneOffJobBootstrap, \"jobScheduler\");\n        return (Scheduler) ReflectionUtils.getFieldValue(jobScheduler.getJobScheduleController(), \"scheduler\");\n    }\n    \n    private void blockUtilFinish(final OneOffJobBootstrap oneOffJobBootstrap, final AtomicInteger counter) {\n        Scheduler scheduler = getScheduler(oneOffJobBootstrap);\n        Awaitility.await().pollDelay(100L, TimeUnit.MILLISECONDS).until(() -> 0 != counter.get() && scheduler.getCurrentlyExecutingJobs().isEmpty());\n    }\n}\n"
  },
  {
    "path": "bootstrap/src/test/java/org/apache/shardingsphere/elasticjob/bootstrap/type/ScheduleJobBootstrapTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.bootstrap.type;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.curator.CuratorZookeeperClient;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.test.TestingServer;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.quartz.core.JobRunShell;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.time.LocalTime;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.Logger;\n\n@Slf4j\nclass ScheduleJobBootstrapTest {\n    \n    private TestingServer testingServer;\n    \n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeEach\n    void beforeEach() throws Exception {\n        testingServer = new TestingServer();\n        try (\n                CuratorZookeeperClient client = new CuratorZookeeperClient(testingServer.getConnectString(),\n                        60000, 500, null,\n                        new ExponentialBackoffRetry(500, 3, 1500))) {\n            client.start();\n            Awaitility.await().atMost(Duration.ofSeconds(30L)).ignoreExceptions().until(client::isConnected);\n        }\n        regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(testingServer.getConnectString(), \"elasticjob-test\"));\n        regCenter.init();\n    }\n    \n    @AfterEach\n    void afterEach() throws IOException {\n        regCenter.close();\n        testingServer.close();\n    }\n    \n    @Test\n    void testWhenShutdownThenTaskCanCaptureInterruptedException() {\n        Logger jobRunShell = (Logger) LoggerFactory.getLogger(JobRunShell.class.getName());\n        Logger errorLogger = (Logger) LoggerFactory.getLogger(\"org.quartz.core.ErrorLogger\");\n        Level originJobRunShellLevel = jobRunShell.getLevel();\n        Level originErrorLoggerLevel = errorLogger.getLevel();\n        try {\n            jobRunShell.setLevel(Level.OFF);\n            errorLogger.setLevel(Level.OFF);\n            testCaptureInterruptedException(1);\n            testCaptureInterruptedException(2);\n        } finally {\n            jobRunShell.setLevel(originJobRunShellLevel);\n            errorLogger.setLevel(originErrorLoggerLevel);\n        }\n    }\n    \n    @SuppressWarnings({\"InfiniteLoopStatement\", \"BusyWait\"})\n    private void testCaptureInterruptedException(final int shardingTotalCount) {\n        String jobName = \"testTaskCaptureInterruptedTask\" + shardingTotalCount;\n        AtomicBoolean captured = new AtomicBoolean(false);\n        AtomicBoolean running = new AtomicBoolean(false);\n        LocalTime magicTime = LocalTime.now().plusSeconds(2L);\n        String cronExpression = String.format(\"%d %d %d * * ?\", magicTime.getSecond(), magicTime.getMinute(), magicTime.getHour());\n        SimpleJob job = shardingContext -> {\n            try {\n                running.set(true);\n                while (true) {\n                    Thread.sleep(100L);\n                }\n            } catch (final InterruptedException ex) {\n                captured.set(true);\n                Thread.currentThread().interrupt();\n            }\n        };\n        ScheduleJobBootstrap bootstrap = new ScheduleJobBootstrap(regCenter, job, JobConfiguration.newBuilder(jobName, shardingTotalCount).cron(cronExpression).build());\n        bootstrap.schedule();\n        Awaitility.await().atMost(30L, TimeUnit.SECONDS).ignoreExceptions().until(running::get);\n        bootstrap.shutdown();\n        Awaitility.await().atMost(10L, TimeUnit.SECONDS).ignoreExceptions().until(captured::get);\n    }\n}\n"
  },
  {
    "path": "bootstrap/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n            <level>ERROR</level>\n        </filter>\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService\" level=\"OFF\" />\n    <logger name=\"org.apache.curator.framework.listen.MappingListenerManager\" level=\"OFF\" />\n</configuration>\n"
  },
  {
    "path": "distribution/bin/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-distribution</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-bin-distribution</artifactId>\n    <packaging>pom</packaging>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-bootstrap</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-spring-namespace</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-spring-boot-starter</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-email</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-wechat</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n    </dependencies>\n    \n    <profiles>\n        <profile>\n            <id>release</id>\n            <build>\n                <plugins>\n                    <plugin>\n                        <artifactId>maven-assembly-plugin</artifactId>\n                        <executions>\n                            <execution>\n                                <id>lite-bin</id>\n                                <goals>\n                                    <goal>single</goal>\n                                </goals>\n                                <phase>package</phase>\n                                <configuration>\n                                    <descriptors>\n                                        <descriptor>src/main/assembly/elasticjob-binary-distribution.xml</descriptor>\n                                    </descriptors>\n                                </configuration>\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <plugin>\n                        <groupId>net.nicoulaj.maven.plugins</groupId>\n                        <artifactId>checksum-maven-plugin</artifactId>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n    </profiles>\n</project>\n"
  },
  {
    "path": "distribution/bin/src/main/assembly/elasticjob-binary-distribution.xml",
    "content": "<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<assembly xmlns=\"http://maven.apache.org/ASSEMBLY/2.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n          xsi:schemaLocation=\"http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd\">\n    <id>lite-bin</id>\n    <formats>\n        <format>tar.gz</format>\n    </formats>\n    <includeBaseDirectory>true</includeBaseDirectory>\n    <baseDirectory>${project.build.finalName}-bin</baseDirectory>\n    \n    <fileSets>\n        <fileSet>\n            <directory>../../</directory>\n            <includes>\n                <include>LICENSE</include>\n                <include>NOTICE</include>\n            </includes>\n        </fileSet>\n        <fileSet>\n            <directory>src/main/release-docs</directory>\n            <includes>\n                <include>**/*</include>\n            </includes>\n            <outputDirectory>.</outputDirectory>\n        </fileSet>\n    </fileSets>\n    \n    <dependencySets>\n        <dependencySet>\n            <useProjectArtifact>true</useProjectArtifact>\n            <unpack>false</unpack>\n            <outputDirectory>./lib</outputDirectory>\n            <includes>\n                <include>org.apache.shardingsphere.elasticjob:*</include>\n            </includes>\n        </dependencySet>\n    </dependencySets>\n</assembly>\n"
  },
  {
    "path": "distribution/bin/src/main/release-docs/README.txt",
    "content": "Welcome to Apache ShardingSphere-ElasticJob\n===============================================================================\n\nElasticJob is a distributed scheduling solution.\n\nThrough the functions of flexible scheduling, resource management and job management, \nit creates a distributed scheduling solution suitable for Internet scenarios, \nand provides a diversified job ecosystem through open architecture design.\nIt uses a unified job API for each project.\nDevelopers only need code one time and can deploy at will.\n\nElasticJob is a lightweight, decentralized solution that provides distributed task sharding services.\n\nElasticJob became an Apache ShardingSphere Sub project on May 28 2020.\n\nGetting Started\n===============================================================================\nTo help you get started, try the following links:\n\nGetting Started\n    https://shardingsphere.apache.org/elasticjob/current/en/quick-start/\n\nWe welcome contributions of all kinds, for details of how you can help\n    https://shardingsphere.apache.org/community/en/contribute/\n\nFind the issue tracker from here\n    https://github.com/apache/shardingsphere-elasticjob/issues\n\nPlease help us make Apache ShardingSphere-ElasticJob better - we appreciate any feedback you may have.\n\nHave fun!\n"
  },
  {
    "path": "distribution/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-distribution</artifactId>\n    <packaging>pom</packaging>\n    <name>${project.artifactId}</name>\n    \n    <modules>\n        <module>src</module>\n        <module>bin</module>\n    </modules>\n    \n    <properties>\n        <maven.deploy.skip>true</maven.deploy.skip>\n    </properties>\n</project>\n"
  },
  {
    "path": "distribution/src/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-distribution</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-src-distribution</artifactId>\n    <packaging>pom</packaging>\n    <name>${project.artifactId}</name>\n    \n    <profiles>\n        <profile>\n            <id>release</id>\n            <build>\n                <plugins>\n                    <plugin>\n                        <artifactId>maven-assembly-plugin</artifactId>\n                        <executions>\n                            <execution>\n                                <id>src</id>\n                                <goals>\n                                    <goal>single</goal>\n                                </goals>\n                                <phase>package</phase>\n                                <configuration>\n                                    <descriptors>\n                                        <descriptor>src/main/assembly/source-distribution.xml</descriptor>\n                                    </descriptors>\n                                </configuration>\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <plugin>\n                        <groupId>net.nicoulaj.maven.plugins</groupId>\n                        <artifactId>checksum-maven-plugin</artifactId>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n    </profiles>\n</project>\n"
  },
  {
    "path": "distribution/src/src/main/assembly/source-distribution.xml",
    "content": "<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<assembly xmlns=\"http://maven.apache.org/ASSEMBLY/2.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n          xsi:schemaLocation=\"http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd\">\n    <id>src</id>\n    <formats>\n        <format>zip</format>\n    </formats>\n    <includeBaseDirectory>true</includeBaseDirectory>\n    <baseDirectory>${project.build.finalName}-src-release</baseDirectory>\n    \n    <fileSets>\n        <fileSet>\n            <directory>../../</directory>\n            <useDefaultExcludes>true</useDefaultExcludes>\n            <includes>\n                <include>**/*</include>\n            </includes>\n            <excludes>\n                <!-- github ignore -->\n                <exclude>**/.github/**</exclude>\n                <exclude>.travis.yml</exclude>\n                \n                <!-- maven ignore -->\n                <exclude>**/target/**</exclude>\n                <exclude>**/*.class</exclude>\n                <exclude>**/*.jar</exclude>\n                <exclude>**/*.war</exclude>\n                <exclude>**/*.zip</exclude>\n                <exclude>**/*.tar</exclude>\n                <exclude>**/*.tar.gz</exclude>\n                <exclude>**/.flattened-pom.xml</exclude>\n                \n                <!-- maven plugin ignore -->\n                <exclude>release.properties</exclude>\n                <exclude>**/pom.xml.releaseBackup</exclude>\n                <exclude>**/cobertura.ser</exclude>\n                <exclude>*.gpg</exclude>\n                \n                <!-- eclipse ignore -->\n                <exclude>**/.settings/**</exclude>\n                <exclude>**/.project</exclude>\n                <exclude>**/.classpath</exclude>\n                \n                <!-- idea ignore -->\n                <exclude>**/.idea/**</exclude>\n                <exclude>**/*.ipr</exclude>\n                <exclude>**/*.iml</exclude>\n                <exclude>**/*.iws</exclude>\n                \n                <!-- temp ignore -->\n                <exclude>**/logs/**</exclude>\n                <exclude>**/*.log</exclude>\n                <exclude>**/*.doc</exclude>\n                <exclude>**/*.cache</exclude>\n                <exclude>**/*.diff</exclude>\n                <exclude>**/*.patch</exclude>\n                <exclude>**/*.tmp</exclude>\n                \n                <!-- system ignore -->\n                <exclude>**/.DS_Store</exclude>\n                <exclude>**/Thumbs.db</exclude>\n                \n                <!-- modules ignore -->\n                <exclude>docs/**</exclude>\n                <exclude>examples/**</exclude>\n            </excludes>\n        </fileSet>\n    </fileSets>\n</assembly>\n"
  },
  {
    "path": "docs/README.md",
    "content": "本文档使用[hugo](http://gohugo.io/overview/introduction/)生成文档。\n同时使用主题[hugo theme learn](https://github.com/matcornic/hugo-theme-learn)来作为文档风格。"
  },
  {
    "path": "docs/archetypes/default.md",
    "content": "---\ntitle: \"{{ replace .Name \"-\" \" \" | title }}\"\ndate: {{ .Date }}\ndraft: true\n---\n\n"
  },
  {
    "path": "docs/build.sh",
    "content": "#!/bin/bash\ncd `dirname $0`\n\nrm -rf public\n\nhugo\nfind ./ -name '*.html' -exec sed -i -e 's|[[:space:]]*<option id=\"\\([a-zA-Z]\\+\\)\" value=\"|<option id=\"\\1\" value=\"/elasticjob/current|g' {} \\;\ncd public/en\nsed -i -e 's/cn/en/g' index.html\n\ncd ..\n"
  },
  {
    "path": "docs/config.toml",
    "content": "baseURL = \"https://shardingsphere.apache.org/elasticjob/current/\"\ncanonifyurls = true\nlanguageCode = \"en-us\"\ntitle = \"ElasticJob\"\ntheme = \"hugo-theme-learn\"\n\ndefaultContentLanguage = \"en\"\ndefaultContentLanguageInSubdir= true\n\n[Languages]\n[Languages.en]\n#baseURL = \"https://shardingsphere.apache.org/elasticjob/current/\"\ntitle = \"ElasticJob\"\nweight = 1\nlanguageName = \"English\"\n\n[Languages.cn]\n#baseURL = \"https://shardingsphere.apache.org/elasticjob/current/\"\ntitle = \"ElasticJob\"\nweight = 2\nlanguageName = \"简体中文\"\n\n[params]\n# Change default color scheme with a variant one. Can be \"red\", \"blue\", \"green\".\nthemeVariant = \"white\"\n# Disable search function. It will hide search bar\ndisableSearch = false\neditURL = \"https://github.com/apache/shardingsphere-elasticjob/tree/master/docs/content/\"\n\n[markup]\n[markup.tableOfContents]\nendLevel = 3\nordered = false\nstartLevel = 2\n\n[markup.goldmark]\n[markup.goldmark.renderer]\nunsafe = true\n"
  },
  {
    "path": "docs/content/blog/_index.cn.md",
    "content": "+++\npre = \"<b>9. </b>\"\ntitle = \"博客\"\nweight = 9\nchapter = true\n+++\n\n* 2020-07 [InfoQ文章：ElasticJob的产品定位与新版本设计理念](https://www.infoq.cn/article/ZcEsH20kUCB9QP1O1PNt)\n\n* 2020-07 [开源中国：GitHub上持续冲榜，ElasticJob重启](https://mp.weixin.qq.com/s/QLKjn_dfVG2OBxbnrwDl5w)\n\n* 2020-05 [官微快讯：分布式调度项目ElasticJob即将重新起航](https://mp.weixin.qq.com/s/XJFj_vOj3bR6HRQUzy1ikg)\n\n* 2017-09 [Mesosphere新闻：Q&A with Zhang Liang of Dangdang: the biggest book seller in China](https://mesosphere.com/blog/qa-dangdang-book-seller-china/?from=timeline&isappinstalled=0)\n\n* 2017-04 [InfoQ新闻：分布式调度中间件Elastic-Job 2.1.0发布：Cloud Native里程碑版本](http://www.infoq.com/cn/news/2017/04/Elastic-Job-2.1.0)\n\n* 2017-03 [源码分析：Elastic-Job项目源码分析系列](http://blog.csdn.net/spy19881201/article/category/6784965)\n\n* 2015-12 [InfoQ文章：详解当当网的分布式作业框架elastic-job](http://www.infoq.com/cn/articles/dangdang-distributed-work-framework-elastic-job)\n\n* 2015-11 [高可用架构群分享：新一代分布式任务调度框架，elastic-job开源项目的10项特性](http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=401047377&idx=1&sn=2a88e5b10d80e2b8bee289abd2fe4bd1&scene=23&srcid=1105c4GbpUGl6I6PyvRsRWxJ#rd)\n\n* 2015-11 [CSDN专访：深度解读分布式作业调度框架elastic-job](http://www.csdn.net/article/2015-11-23/2826304)\n\n* 2015-09 [InfoQ新闻：当当开源elastic-job，分布式作业调度框架](http://www.infoq.com/cn/news/2015/09/dangdang-elastic-job)\n"
  },
  {
    "path": "docs/content/blog/_index.en.md",
    "content": "+++\npre = \"<b>9. </b>\"\ntitle = \"Blog\"\nweight = 9\nchapter = true\n+++\n\nTODO\n"
  },
  {
    "path": "docs/content/dev-manual/_index.cn.md",
    "content": "+++\npre = \"<b>5. </b>\"\ntitle = \"开发者手册\"\nweight = 5\nchapter = true\n+++\n\nElasticJob 可插拔架构提供了 SPI 的扩展点。\n对于开发者来说，可以十分方便的对功能进行定制化扩展。\n \n本章节将 ElasticJob 的 SPI 扩展点悉数列出。\n如无特殊需求，用户可以使用 ElasticJob 提供的内置实现；\n高级用户则可以参考各个功能模块的接口进行自定义实现。\n\nElasticJob 社区非常欢迎开发者将自己的实现类反馈至[开源社区](https://github.com/apache/shardingsphere-elasticjob/pulls)，让更多用户从中收益。\n"
  },
  {
    "path": "docs/content/dev-manual/_index.en.md",
    "content": "+++\npre = \"<b>5. </b>\"\ntitle = \"Dev Manual\"\nweight = 5\nchapter = true\n+++\n\nElasticJob provides dozens of SPI based extensions. \nit is very convenient to customize the functions for developers.\n\nThis chapter lists all SPI extensions of ElasticJob.\nIf there is no special requirement, users can use the built-in implementation provided by ElasticJob; \nadvanced users can refer to the interfaces for customized implementation.\n\nElasticJob community welcomes developers to feed back their implementations to the [open-source community](https://github.com/apache/shardingsphere-elasticjob/pulls), \nso that more users can benefit from it.\n"
  },
  {
    "path": "docs/content/dev-manual/error-handler.cn.md",
    "content": "+++\npre = \"<b>5.3. </b>\"\ntitle = \"错误处理策略\"\nweight = 3\n+++\n\n错误处理策略，用于作业失败时的处理策略。\n\n| *SPI 名称*              | *详细说明*                         |\n| ----------------------- | --------------------------------- |\n| JobErrorHandler         | 作业执行错误处理策略                 |\n\n| *已知实现类*             | *详细说明*                          |\n| ----------------------- | --------------------------------- |\n| LogJobErrorHandler      | 记录作业异常日志，但不中断作业执行     |\n| ThrowJobErrorHandler    | 抛出系统异常并中断作业执行            |\n| IgnoreJobErrorHandler   | 忽略系统异常且不中断作业执行          |\n| EmailJobErrorHandler    | 发送邮件消息通知，但不中断作业执行     |\n| WechatJobErrorHandler   | 发送企业微信消息通知，但不中断作业执行 |\n| DingtalkJobErrorHandler | 发送钉钉消息通知，但不中断作业执行    |\n"
  },
  {
    "path": "docs/content/dev-manual/error-handler.en.md",
    "content": "+++\npre = \"<b>5.3. </b>\"\ntitle = \"Error Handler\"\nweight = 3\n+++\n\nError handler strategy, used to handle error when exception occur during job execution.\n\n| *SPI Name*               | *Description*                                               |\n| ------------------------ | ----------------------------------------------------------- |\n| JobErrorHandler          | Job error handler                                           |\n\n| *Implementation Class*   | *Description*                                               |\n| ------------------------ | ----------------------------------------------------------- |\n| LogJobErrorHandler       | Log error and do not interrupt job                          |\n| ThrowJobErrorHandler     | Throw system exception and interrupt job                    |\n| IgnoreJobErrorHandler    | Ignore exception and do not interrupt job                   |\n| EmailJobErrorHandler     | Send email message notification and do not interrupt job    |\n| WechatJobErrorHandler    | Send wechat message notification and do not interrupt job   |\n| DingtalkJobErrorHandler  | Send dingtalk message notification and do not interrupt job |\n"
  },
  {
    "path": "docs/content/dev-manual/job-class-provider.cn.md",
    "content": "+++\npre = \"<b>5.4. </b>\"\ntitle = \"作业类名称提供策略\"\nweight = 4\n+++\n\n作业类名称提供策略，用于在不同的容器环境下提供准确的作业类名称。\n\n| *SPI 名称*                       | *详细说明*                        |\n| ------------------------------- | --------------------------------- |\n| JobClassNameProvider            | 作业类名称提供策略                  |\n\n| *已知实现类*                     | *详细说明*                         |\n| ------------------------------- | --------------------------------- |\n| DefaultJobClassNameProvider     | 标准环境下的作业类名称提供策略        |\n| SpringProxyJobClassNameProvider | Spring 容器环境下的作业类名称提供策略 |\n"
  },
  {
    "path": "docs/content/dev-manual/job-class-provider.en.md",
    "content": "+++\npre = \"<b>5.4. </b>\"\ntitle = \"Job Class Name Provider\"\nweight = 4\n+++\n\nJob class name provider, used to provide job class name in different contain environments.\n\n| *SPI Name*                      | *Description*                                           |\n| ------------------------------- | ------------------------------------------------------- |\n| JobClassNameProvider            | Job class name provider                                 |\n\n| *Implementation Class*          | *Description*                                           |\n| ------------------------------- | ------------------------------------------------------- |\n| DefaultJobClassNameProvider     | Job class name provider in standard environment         |\n| SpringProxyJobClassNameProvider | Job class name provider in Spring container environment |\n"
  },
  {
    "path": "docs/content/dev-manual/roadmap.cn.md",
    "content": "+++\npre = \"<b>5.5. </b>\"\ntitle = \"线路规划\"\nweight = 5\nchapter = true\n+++\n\n- [x] Unified Job Config API\n    - [x] Core Config\n    - [x] Type Config\n    - [x] Root Config\n- [x] Job Types\n    - [x] Simple\n    - [x] Dataflow\n    - [x] Script\n    - [x] Http（3.0.0-beta 提供）\n- [x] Event Trace\n    - [x] Event Publisher\n    - [x] Database Event Listener\n    - [ ] Other Event Listener\n- [ ] Unified Schedule API\n- [ ] Unified Resource API\n- [x] Distributed Features\n    - [x] High Availability\n    - [x] Elastic scale in/out\n    - [x] Failover\n    - [x] Misfire\n    - [x] Idempotency\n    - [x] Reconcile\n- [x] Registry Center\n    - [x] ZooKeeper\n    - [ ] Other Registry Center Supported\n- [x] Lifecycle Management\n    - [x] Add/Remove\n    - [x] Pause/Resume\n    - [x] Disable/Enable\n    - [x] Shutdown\n    - [x] Restful API\n    - [x] Web Console\n- [x] Job Dependency\n    - [x] Listener\n    - [ ] DAG\n- [x] Spring Integrate\n    - [x] Namespace\n    - [x] Bean Injection\n    - [x] Spring Boot Starter（3.0.0-alpha 提供）\n"
  },
  {
    "path": "docs/content/dev-manual/roadmap.en.md",
    "content": "+++\npre = \"<b>5.5. </b>\"\ntitle = \"Roadmap\"\nweight = 5\nchapter = true\n+++\n\n- [x] Unified Job Config API\n    - [x] Core Config\n    - [x] Type Config\n    - [x] Root Config\n- [x] Job Types\n    - [x] Simple\n    - [x] Dataflow\n    - [x] Script\n    - [x] Http (Since 3.0.0-beta)\n- [x] Event Trace\n    - [x] Event Publisher\n    - [x] Database Event Listener\n    - [ ] Other Event Listener\n- [ ] Unified Schedule API\n- [ ] Unified Resource API\n- [x] Distributed Features\n    - [x] High Availability\n    - [x] Elastic scale in/out\n    - [x] Failover\n    - [x] Misfire\n    - [x] Idempotency\n    - [x] Reconcile\n- [x] Registry Center\n    - [x] ZooKeeper\n    - [ ] Other Registry Center Supported\n- [x] Lifecycle Management\n    - [x] Add/Remove\n    - [x] Pause/Resume\n    - [x] Disable/Enable\n    - [x] Shutdown\n    - [x] Restful API\n    - [x] Web Console\n- [x] Job Dependency\n    - [x] Listener\n    - [ ] DAG\n- [x] Spring Integrate\n    - [x] Namespace\n    - [x] Bean Injection\n    - [x] Spring Boot Starter (Since 3.0.0-alpha)\n"
  },
  {
    "path": "docs/content/dev-manual/sharding.cn.md",
    "content": "+++\npre = \"<b>5.1. </b>\"\ntitle = \"作业分片策略\"\nweight = 1\nchapter = true\n+++\n\n作业分片策略，用于将作业在分布式环境下分解成为任务使用。\n\n| *SPI 名称*                             | *详细说明*                                                     |\n| ------------------------------------- | ------------------------------------------------------------- |\n| JobShardingStrategy                   | 作业分片策略                                                    |\n\n| *已知实现类*                           | *详细说明*                                                      |\n| ------------------------------------- | -------------------------------------------------------------- |\n| AverageAllocationJobShardingStrategy  | 根据分片项平均分片                                               |\n| OdevitySortByNameJobShardingStrategy  | 根据作业名称哈希值的奇偶数决定按照作业服务器 IP 升序或是降序的方式分片 |\n| RotateServerByNameJobShardingStrategy | 根据作业名称轮询分片                                             |\n"
  },
  {
    "path": "docs/content/dev-manual/sharding.en.md",
    "content": "+++\npre = \"<b>5.1. </b>\"\ntitle = \"Job Sharding Strategy\"\nweight = 1\nchapter = true\n+++\n\nJob Sharding Strategy， used to sharding job to distributed tasks.\n\n| *SPI Name*                            | *Description*                                               |\n| ------------------------------------- | ----------------------------------------------------------- |\n| JobShardingStrategy                   | Job sharding strategy                                       |\n\n| *Implementation Class*                | *Description*                                               |\n| ------------------------------------- | ----------------------------------------------------------- |\n| AverageAllocationJobShardingStrategy  | Sharding or average by sharding item                        |\n| OdevitySortByNameJobShardingStrategy  | Sharding for hash with job name to determine IP asc or desc |\n| RotateServerByNameJobShardingStrategy | Sharding for round robin by name job                        |\n"
  },
  {
    "path": "docs/content/dev-manual/thread-pool.cn.md",
    "content": "+++\npre = \"<b>5.2. </b>\"\ntitle = \"线程池策略\"\nweight = 2\n+++\n\n线程池策略，用于执行作业的线程池创建。\n\n| *SPI 名称*                          | *详细说明*       |\n|-----------------------------------|--------------|\n| JobExecutorThreadPoolSizeProvider | 作业执行线程数量提供策略 |\n\n| *已知实现类*                                       | *详细说明*                  |\n|-----------------------------------------------|-------------------------|\n| CPUUsageJobExecutorThreadPoolSizeProvider     | 根据 CPU 核数 * 2 创建作业处理线程池 |\n| SingleThreadJobExecutorThreadPoolSizeProvider | 使用单线程处理作业               |\n"
  },
  {
    "path": "docs/content/dev-manual/thread-pool.en.md",
    "content": "+++\npre = \"<b>5.2. </b>\"\ntitle = \"Thread Pool Strategy\"\nweight = 2\n+++\n\nThread pool strategy, used to create thread pool for job execution. \n\n| *SPI Name*                        | *Description*                          |\n|-----------------------------------|----------------------------------------|\n| JobExecutorThreadPoolSizeProvider | Job executor thread pool size provider |\n\n| *Implementation Class*                        | *Description*                                          |\n|-----------------------------------------------|--------------------------------------------------------|\n| CPUUsageJobExecutorThreadPoolSizeProvider     | Use CPU available processors * 2 to create thread pool |\n| SingleThreadJobExecutorThreadPoolSizeProvider | Use single thread to execute job                       |\n"
  },
  {
    "path": "docs/content/downloads/_index.cn.md",
    "content": "+++\npre = \"<b>6. </b>\"\ntitle = \"下载\"\nweight = 6\nchapter = true\n\nextracss = true\n\n+++\n\n## 最新版本\n\nElasticJob 的发布版包括源码包及其对应的二进制包。\n由于下载内容分布在镜像服务器上，所以下载后应该进行 GPG 或 SHA-512 校验，以此来保证内容没有被篡改。\n\n##### ElasticJob - 版本: 3.0.5 ( 发布日期: Feb 7, 2026 )\n\nhttps://www.apache.org/dyn/closer.lua/PROJECT/VERSION/SOURCE-RELEASE\n\n- 源码: [ [SRC](https://www.apache.org/dyn/closer.lua/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-src.zip) ] [ [ASC](https://downloads.apache.org/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-src.zip.asc) ] [ [SHA512](https://downloads.apache.org/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-src.zip.sha512) ]\n- ElasticJob 二进制包: [ [TAR](https://www.apache.org/dyn/closer.lua/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-lite-bin.tar.gz) ] [ [ASC](https://downloads.apache.org/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-lite-bin.tar.gz.asc) ] [ [SHA512](https://downloads.apache.org/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-lite-bin.tar.gz.sha512) ]\n\n##### ElasticJob-UI - 版本: 3.0.2 ( 发布日期: Oct 31, 2022 )\n\n- 源码: [ [SRC](https://www.apache.org/dyn/closer.lua/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-ui-src.zip) ] [ [ASC](https://downloads.apache.org/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-ui-src.zip.asc) ] [ [SHA512](https://downloads.apache.org/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-ui-src.zip.sha512) ]\n- ElasticJob-UI 二进制包: [ [TAR](https://www.apache.org/dyn/closer.lua/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-lite-ui-bin.tar.gz) ] [ [ASC](https://downloads.apache.org/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-lite-ui-bin.tar.gz.asc) ] [ [SHA512](https://downloads.apache.org/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-lite-ui-bin.tar.gz.sha512) ]\n\n即将发布\n\n## 全部版本\n\n全部版本请到 [Archive repository](https://archive.apache.org/dist/shardingsphere/) 查看。\n\n## 校验版本\n\n[PGP签名文件](https://downloads.apache.org/shardingsphere/KEYS)\n\n使用 PGP 或 SHA 签名验证下载文件的完整性至关重要。\n可以使用 GPG 或 PGP 验证 PGP 签名。\n请下载 KEYS 以及发布的 asc 签名文件。\n建议从主发布目录而不是镜像中获取这些文件。\n\n```shell\ngpg -i KEYS\n```\n\n或者\n\n```shell\npgpk -a KEYS\n```\n\n或者\n\n```shell\npgp -ka KEYS\n```\n\n要验证二进制文件或源代码，您可以从主发布目录下载相关的 asc 文件，并按照以下指南进行操作。\n\n```shell\ngpg --verify apache-shardingsphere-elasticjob-********.asc apache-shardingsphere-elasticjob-*********\n```\n\n或者\n\n```shell\npgpv apache-shardingsphere-elasticjob-********.asc\n```\n\n或者\n\n```shell\npgp apache-shardingsphere-elasticjob-********.asc\n```\n"
  },
  {
    "path": "docs/content/downloads/_index.en.md",
    "content": "+++\npre = \"<b>6. </b>\"\ntitle = \"Downloads\"\nweight = 6\nchapter = true\n\nextracss = true\n\n+++\n\n## Latest Releases\n\nElasticJob is released as source code tarballs with corresponding binary tarballs for convenience. \nThe downloads are distributed via mirror sites and should be checked for tampering using GPG or SHA-512.\n\n##### ElasticJob - Version: 3.0.5 ( Release Date: Feb 7, 2026 )\n\n- Source Codes: [ [SRC](https://www.apache.org/dyn/closer.lua/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-src.zip) ] [ [ASC](https://downloads.apache.org/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-src.zip.asc) ] [ [SHA512](https://downloads.apache.org/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-src.zip.sha512) ]\n- ElasticJob Binary Distribution: [ [TAR](https://www.apache.org/dyn/closer.lua/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-lite-bin.tar.gz) ] [ [ASC](https://downloads.apache.org/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-lite-bin.tar.gz.asc) ] [ [SHA512](https://downloads.apache.org/shardingsphere/elasticjob-3.0.5/apache-shardingsphere-elasticjob-3.0.5-lite-bin.tar.gz.sha512) ]\n\n##### ElasticJob-UI - Version: 3.0.2 ( Release Date: Oct 31, 2022 )\n\n- Source Codes: [ [SRC](https://www.apache.org/dyn/closer.lua/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-ui-src.zip) ] [ [ASC](https://downloads.apache.org/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-ui-src.zip.asc) ] [ [SHA512](https://downloads.apache.org/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-ui-src.zip.sha512) ]\n- ElasticJob-UI Binary Distribution: [ [TAR](https://www.apache.org/dyn/closer.lua/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-lite-ui-bin.tar.gz) ] [ [ASC](https://downloads.apache.org/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-lite-ui-bin.tar.gz.asc) ] [ [SHA512](https://downloads.apache.org/shardingsphere/elasticjob-ui-3.0.2/apache-shardingsphere-elasticjob-3.0.2-lite-ui-bin.tar.gz.sha512) ]\n\n## All Releases\n\nFind all releases in the [Archive repository](https://archive.apache.org/dist/shardingsphere/).\n\n## Verify the Releases\n\n[PGP signatures KEYS](https://downloads.apache.org/shardingsphere/KEYS)\n\nIt is essential that you verify the integrity of the downloaded files using the PGP or SHA signatures. \nThe PGP signatures can be verified using GPG or PGP. Please download the KEYS as well as the asc signature files for relevant distribution. \nIt is recommended to get these files from the main distribution directory and not from the mirrors.\n\n```shell\ngpg -i KEYS\n```\n\nor\n\n```shell\npgpk -a KEYS\n```\n\nor\n\n```shell\npgp -ka KEYS\n```\n\nTo verify the binaries/sources you can download the relevant asc files for it from main distribution directory and follow the below guide.\n\n```shell\ngpg --verify apache-shardingsphere-********.asc apache-shardingsphere-elasticjob-*********\n```\n\nor\n\n```shell\npgpv apache-shardingsphere-elasticjob-********.asc\n```\n\nor\n\n```shell\npgp apache-shardingsphere-elasticjob-********.asc\n```\n"
  },
  {
    "path": "docs/content/faq/_index.cn.md",
    "content": "+++\npre = \"<b>8. </b>\"\ntitle = \"FAQ\"\nweight = 8\nchapter = true\n+++\n\n## 1. 阅读源码时为什么会出现编译错误?\n\n回答：\n\nElasticJob 使用 lombok 实现极简代码。关于更多使用和安装细节，请参考 [lombok 官网](https://projectlombok.org/download)。\n\n## 2. 是否支持动态添加作业?\n\n回答：\n\n动态添加作业这个概念每个人理解不尽相同。\n\nElasticJob 为 jar 包，由开发或运维人员负责启动。启动时自动向注册中心注册作业信息并进行分布式协调，因此并不需要手工在注册中心填写作业信息。\n但注册中心与作业部署机无从属关系，注册中心并不能控制将单点的作业分发至其他作业机，也无法将远程服务器未启动的作业启动。\nElasticJob 并不会包含 ssh 免密管理等功能。\n\n综上所述，ElasticJob 已做了基本动态添加功能，但无法做到真正意义的完全自动化添加。\n\n## 3. 为什么在代码或配置文件中修改了作业配置，注册中心配置却没有更新?\n\n回答：\n\nElasticJob 采用无中心化设计，若每个客户端的配置不一致，不做控制的话，最后一个启动的客户端配置将会成为注册中心的最终配置。\n\nElasticJob 提出了 overwrite 概念，可通过 JobConfiguration 或 Spring 命名空间配置。\n`overwrite=true` 即允许客户端配置覆盖注册中心，反之则不允许。\n如果注册中心无相关作业的配置，则无论 overwrite 是否配置，客户端配置都将写入注册中心。\n\n## 4. 作业与注册中心无法通信会如何?\n\n回答：\n\n为了保证作业的在分布式场景下的一致性，一旦作业与注册中心无法通信，运行中的作业会立刻停止执行，但作业的进程不会退出。\n这样做的目的是为了防止作业重分片时，将与注册中心失去联系的节点执行的分片分配给另外节点，导致同一分片在两个节点中同时执行。\n当作业节点恢复与注册中心联系时，将重新参与分片并恢复执行新的分配到的分片。\n\n## 5. ElasticJob 有何使用限制?\n\n回答：\n\n* 作业启动成功后修改作业名称视为新作业，原作业废弃。\n\n* 一旦有服务器波动，或者修改分片项，将会触发重新分片；触发重新分片将会导致运行中的流式处理的作业在执行完本次作业后不再继续执行，等待分片结束后再恢复正常。\n\n* 开启 monitorExecution 才能实现分布式作业幂等性（即不会在多个作业服务器运行同一个分片）的功能，但 monitorExecution 对短时间内执行的作业（如秒级触发）性能影响较大，建议关闭并自行实现幂等性。\n\n## 6. 怀疑 ElasticJob 在分布式环境中有问题，但无法重现又不能在线上环境调试，应该怎么做?\n\n回答：\n\n分布式问题非常难于调试和重现，为此 ElasticJob 提供了 dump 命令。\n\n如果您怀疑某些场景出现问题，可参照[作业信息导出](/cn/user-manual/elasticjob/operation/dump/)将作业运行时信息提交至社区。\nElasticJob 已将 IP 地址等敏感信息过滤，导出的信息可在公网安全传输。\n\n## 7. 控制台界面无法正常显示?\n\n回答：\n\n使用控制台时应确保与 ElasticJob 相关版本保持一致，否则会导致不可用。\n\n## 8. 为什么控制台界面中的作业状态是分片待调整?\n\n回答：\n\n分片待调整表示作业已启动但尚未获得分片时的状态。\n\n## 9. 为什么首次启动存在任务调度延迟的情况？\n\n回答：\nElasticJob 执行任务会获取本机IP，首次可能存在获取IP较慢的情况。尝试设置 `-Djava.net.preferIPv4Stack=true`.\n\n\n## 10. Windows环境下，运行ShardingSphere-ElasticJob-UI，找不到或无法加载主类 org.apache.shardingsphere.elasticjob.kernel.ui.Bootstrap，如何解决？\n\n回答：\n\n某些解压缩工具在解压ShardingSphere-ElasticJob-UI二进制包时可能将文件名截断，导致找不到某些类。\n\n解决方案：\n\n打开cmd.exe并执行下面的命令：\n\n```bash\ntar zxvf apache-shardingsphere-elasticjob-${RELEASE.VERSION}-lite-ui-bin.tar.gz\n```\n\n## 11. 运行 Cloud Scheduler 持续输出日志 \"Elastic job: IP:PORT has leadership\"，不能正常运行\n\n回答：\n\nCloud Scheduler 依赖 Mesos 库，启动时需要通过 `-Djava.library.path` 指定 Mesos 库所在目录。\n\n例如，Mesos 库位于 `/usr/local/lib`，启动 Cloud Scheduler 前需要设置 `-Djava.library.path=/usr/local/lib`。\n\nMesos 相关请参考 [Apache Mesos](https://mesos.apache.org/)。\n\n## 12. 在多网卡的情况下无法获取到合适的 IP\n\n回答：\n\n可以通过系统变量 `elasticjob.preferred.network.interface` 指定网卡或 `elasticjob.preferred.network.ip` 指定IP地址。\n\n例如:\n\n1. 指定网卡 eno1：`-Delasticjob.preferred.network.interface=eno1`。\n1. 指定IP地址 192.168.0.100：`-Delasticjob.preferred.network.ip=192.168.0.100`。\n1. 泛指IP地址(正则表达式) 192.168.*：`-Delasticjob.preferred.network.ip=192.168.*`。\n\n## 13. zk授权升级,在滚动部署过程中出现实例假死,回退到历史版本也依然存在假死。\n\n回答:\n\n在滚动部署过程中,会触发竞争选举leader,有密码的实例会给zk目录加密导致无密码的实例不可访问,最终导致整体选举阻塞。\n\n例如:\n\n通过日志可以发现会抛出-102异常:\n\n```bash\nxxxx-07-27 22:33:55.224 [DEBUG] [localhost-startStop-1-EventThread] [] [] [] - o.a.c.f.r.c.TreeCache : processResult: CuratorEventImpl{type=GET_DATA, resultCode=-102, path='/xxx/leader/election/latch/_c_bccccdcc-1134-4e0a-bb52-59a13836434a-latch-0000000047', name='null', children=null, context=null, stat=null, data=null, watchedEvent=null, aclList=null}\n```\n\n解决方案:\n\n1.如果您在升级的过程中出现回退历史版本也依然假死的问题,建议删除zk上所有作业目录,之后再重启历史版本。\n2.计算出合理的作业执行间隙,比如晚上21:00-21:30作业不会触发,在此期间先将实例全部停止,然后将带密码的版本全部部署上线。\n"
  },
  {
    "path": "docs/content/faq/_index.en.md",
    "content": "+++\npre = \"<b>8. </b>\"\ntitle = \"FAQ\"\nweight = 8\nchapter = true\n+++\n\n## 1. Why do some compiling errors appear?\n\nAnswer:\n\n`ElasticJob` uses `lombok` to enable minimal coding. For more details about using and installment, please refer to the official website of [lombok](https://projectlombok.org/download).\n\n## 2. Does ElasticJob support dynamically adding jobs?\n\nAnswer:\n\nFor the concept of dynamically adding job, everyone has a different understanding.\n\n`ElasticJob` is provided in jar package, which is started by developers or operation. When the job is started, it will automatically register job information to the registry center, and the registry center will perform distributed coordination, so there is no need to manually add job information in the registry center.\nHowever, registry center has no affiliation with the job server, can't control the distribution of single-point jobs to other job machines, and also can't start the job of remote server.\n`ElasticJob` doesn't support ssh secret management and other functions.\n\nIn summary, `ElasticJob` has supported basic dynamically adding jobs, but it can't be fully automated.\n\n## 3. Why is the job configuration modified in the code or Spring XML file, but the registry center is not updated?\n\nAnswer:\n\n`ElasticJob` adopts a decentralized design. If the configuration of each client is inconsistent and is not controlled, the configuration of the client which is last started will be the final configuration of the registry center.\n\n`ElasticJob` proposes the concept of `overwrite`, which can be configured through `JobConfiguration` or `Spring` namespace.\n`overwrite=true` indicates that the client's configuration is allowed to override the registry center, and on the contrary is not allowed.\nIf there is no configuration of related jobs in the registry center, regardless of whether the property of `overwrite` is configured, the client's configuration will be still written into the registry center.\n\n## 4. What happens if the job can't communicate with the registry center?\n\nAnswer:\n\nIn order to ensure the consistency of the job in the distributed system, once the job can't communicate with the registry center, the job will stop immediately, but the job's process will not exit.\nThe purpose of this is to prevent the assignment of the shards executed by the node that has lost contact with the registry center to another node when the job is re-sharded, causing the same shard to be executed on both nodes at the same time.\nWhen the node resumes contact with the registry center, it will re-participate in the sharding and resume execution of the newly shard.\n\n## 5. What are the usage restrictions of `ElasticJob`?\n\nAnswer:\n\n* After the job start successfully, modifying the job name is regarded as a new job, and the original job is discarded.\n\n* It will be triggered re-sharding if the server changes, or if the sharding item is modified; re-sharding will cause the running streaming job to stop after the job is executed, and this job will return to normal after the re-sharding is finished.\n\n* Enable `monitorExecution` to realize the function of distributed job idempotence (that is, the same shard will not be run on different job servers), but `monitorExecution` has a greater impact on the performance of jobs executed in a short period of time (such as second-level triggers). It is recommended to turn it off and realize idempotence by yourself.\n\n## 6. What should you do if you suspect that `ElasticJob` has a problem in a distributed environment, but it cannot be reproduced and cannot be debugged in the online environment?\n\nAnswer:\n\nDistributed problems are very difficult to debug and reproduce. For this reason, `ElasticJob` provides the `dump` command.\n\nIf you suspect a problem in some scenarios, you can refer to the [dump](/en/user-manual/elasticjob/operation/dump/) document to submit the job runtime information to the community.\n`ElasticJob` has filtered sensitive information such as `IP`, and the dump file can be safely transmitted on the Internet.\n\n## 7. Why can't the Console page display normally?\n\nAnswer:\n\nMake sure that the `Web Console`'s version is consistent with `ElasticJob`, otherwise it will become unavailable.\n\n## 8. Why is the job state shard to be adjusted in the Console?\n\nAnswer:\n\nShard to be adjusted indicates the state when the job has started but has not yet obtained the shard.\n\n## 9. Why is there a task scheduling delay in the first startup?\n\nAnswer:\n\nElasticJob will obtain the local IP when performing task scheduling, and it may be slow to obtain the IP for the first time. Try to set `-Djava.net.preferIPv4Stack=true`.\n\n\n## 10. In Windows env, run ShardingSphere-ElasticJob-UI, could not find or load main class org.apache.shardingsphere.elasticjob.kernel.ui.Bootstrap. Why?\n\nAnswer:\n\nSome decompression tools may truncate the file name when decompressing the ShardingSphere-ElasticJob-UI binary package, resulting in some classes not being found\n\nOpen cmd.exe and execute the following command:\n\n```bash\ntar zxvf apache-shardingsphere-elasticjob-${RELEASE.VERSION}-lite-ui-bin.tar.gz\n```\n\n## 11. Unable to startup Cloud Scheduler. Continuously output \"Elastic job: IP:PORT has leadership\"\n\nAnswer: \n\nCloud Scheduler required Mesos native library. Specify Mesos native library path by property `-Djava.library.path`.\n\nFor instance, Mesos native libraries are under `/usr/local/lib`, so the property `-Djava.library.path=/usr/local/lib` need to be set to start the Cloud Scheduler.\n\nAbout Apache Mesos, please refer to [Apache Mesos](https://mesos.apache.org/).\n\n## 12. Unable to obtain a suitable IP in the case of multiple network interfaces\n\nAnswer: \n\nYou may specify interface by system property `elasticjob.preferred.network.interface` or specify IP by system property `elasticjob.preferred.network.ip`.\n\nFor example\n\n1. specify the interface eno1: `-Delasticjob.preferred.network.interface=eno1`.\n1. specify network addresses, 192.168.0.100: `-Delasticjob.preferred.network.ip=192.168.0.100`.\n1. specify network addresses for regular expressions, 192.168.*: `-Delasticjob.preferred.network.ip=192.168.*`.\n\n## 13. During the zk authorization upgrade process, there was a false death of the instance during the rolling deployment process, and even if the historical version was rolled back, there was still false death.\n\nAnswer:\n\nDuring the rolling deployment process, competitive election leaders will be triggered, and instances with passwords will encrypt the zk directory, making instances without passwords inaccessible, ultimately leading to overall election blocking.\n\nFor example\n\nThrough the logs, it can be found that an -102 exception will be thrown:\n\n```bash\nxxxx-07-27 22:33:55.224 [DEBUG] [localhost-startStop-1-EventThread] [] [] [] - o.a.c.f.r.c.TreeCache : processResult: CuratorEventImpl{type=GET_DATA, resultCode=-102, path='/xxx/leader/election/latch/_c_bccccdcc-1134-4e0a-bb52-59a13836434a-latch-0000000047', name='null', children=null, context=null, stat=null, data=null, watchedEvent=null, aclList=null}\n```\n\n1. If you encounter the issue of returning to the historical version and still pretending to be dead during the upgrade process, it is recommended to delete all job directories on zk and restart the historical version afterwards.\n2. Calculate a reasonable job execution gap, such as when the job will not trigger from 21:00 to 21:30 in the evening. During this period, first stop all instances, and then deploy all versions with passwords online.\n"
  },
  {
    "path": "docs/content/features/_index.cn.md",
    "content": "+++\npre = \"<b>3. </b>\"\ntitle = \"概念 & 功能\"\nweight = 3\nchapter = true\n+++\n\n本章节阐述 ElasticJob 相关的概念与功能，更多使用细节请阅读[用户手册](/cn/user-manual/)。"
  },
  {
    "path": "docs/content/features/_index.en.md",
    "content": "+++\npre = \"<b>3. </b>\"\ntitle = \"Concepts & Features\"\nweight = 3\nchapter = true\n+++\n\nThis chapter describes concepts and features about ElasticJob. \nPlease refer to [User manual](/en/user-manual/) for more details.\n"
  },
  {
    "path": "docs/content/features/elastic.cn.md",
    "content": "+++\npre = \"<b>3.2. </b>\"\ntitle = \"弹性调度\"\nweight = 2\nchapter = true\n+++\n\n弹性调度是 ElasticJob 最重要的功能，也是这款产品名称的由来。\n它是一款能够让任务通过分片进行水平扩展的任务处理系统。\n\n## 分片\n\nElasticJob 中任务分片项的概念，使得任务可以在分布式的环境下运行，每台任务服务器只运行分配给该服务器的分片。\n随着服务器的增加或宕机，ElasticJob 会近乎实时的感知服务器数量的变更，从而重新为分布式的任务服务器分配更加合理的任务分片项，使得任务可以随着资源的增加而提升效率。\n\n任务的分布式执行，需要将一个任务拆分为多个独立的任务项，然后由分布式的服务器分别执行某一个或几个分片项。\n\n举例说明，如果作业分为 4 片，用两台服务器执行，则每个服务器分到 2 片，分别负责作业的 50% 的负载，如下图所示。\n\n![分片作业](https://shardingsphere.apache.org/elasticjob/current/img/elastic/sharding.png)\n\n### 分片项\n\nElasticJob 并不直接提供数据处理的功能，而是将分片项分配至各个运行中的作业服务器，开发者需要自行处理分片项与业务的对应关系。\n分片项为数字，始于 0 而终于分片总数减 1。\n\n### 个性化分片参数\n\n个性化参数可以和分片项匹配对应关系，用于将分片项的数字转换为更加可读的业务代码。\n\n例如：按照地区水平拆分数据库，数据库 A 是北京的数据；数据库 B 是上海的数据；数据库 C 是广州的数据。\n如果仅按照分片项配置，开发者需要了解 0 表示北京；1 表示上海；2 表示广州。\n合理使用个性化参数可以让代码更可读，如果配置为 0=北京,1=上海,2=广州，那么代码中直接使用北京，上海，广州的枚举值即可完成分片项和业务逻辑的对应关系。\n\n## 资源最大限度利用\n\nElasticJob 提供最灵活的方式，最大限度的提高执行作业的吞吐量。\n当新增加作业服务器时，ElasticJob 会通过注册中心的临时节点的变化感知到新服务器的存在，并在下次任务调度的时候重新分片，新的服务器会承载一部分作业分片，如下图所示。\n\n![作业扩容](https://shardingsphere.apache.org/elasticjob/current/img/elastic/sacle-out.png)\n\n将分片项设置为大于服务器的数量，最好是大于服务器倍数的数量，作业将会合理的利用分布式资源，动态的分配分片项。\n\n例如：3 台服务器，分成 10 片，则分片项分配结果为服务器 A = 0,1,2,9；服务器 B = 3,4,5；服务器 C = 6,7,8。\n如果服务器 C 崩溃，则分片项分配结果为服务器 A = 0,1,2,3,4; 服务器 B = 5,6,7,8,9。\n在不丢失分片项的情况下，最大限度的利用现有资源提高吞吐量。\n\n## 高可用\n\n当作业服务器在运行中宕机时，注册中心同样会通过临时节点感知，并将在下次运行时将分片转移至仍存活的服务器，以达到作业高可用的效果。\n本次由于服务器宕机而未执行完的作业，则可以通过失效转移的方式继续执行。如下图所示。\n\n![作业高可用](https://shardingsphere.apache.org/elasticjob/current/img/elastic/ha.png)\n\n将分片总数设置为 1，并使用多于 1 台的服务器执行作业，作业将会以 1 主 n 从的方式执行。\n一旦执行作业的服务器宕机，等待执行的服务器将会在下次作业启动时替补执行。开启失效转移功能效果更好，如果本次作业在执行过程中宕机，备机会立即替补执行。\n\n## 实现原理\n\nElasticJob 并无作业调度中心节点，而是基于部署作业框架的程序在到达相应时间点时各自触发调度。\n注册中心仅用于作业注册和监控信息存储。而主作业节点仅用于处理分片和清理等功能。\n\n### 弹性分布式实现\n\n- 第一台服务器上线触发主服务器选举。主服务器一旦下线，则重新触发选举，选举过程中阻塞，只有主服务器选举完成，才会执行其他任务。\n- 某作业服务器上线时会自动将服务器信息注册到注册中心，下线时会自动更新服务器状态。\n- 主节点选举，服务器上下线，分片总数变更均更新重新分片标记。\n- 定时任务触发时，如需重新分片，则通过主服务器分片，分片过程中阻塞，分片结束后才可执行任务。如分片过程中主服务器下线，则先选举主服务器，再分片。\n- 通过上一项说明可知，为了维持作业运行时的稳定性，运行过程中只会标记分片状态，不会重新分片。分片仅可能发生在下次任务触发前。\n- 每次分片都会按服务器IP排序，保证分片结果不会产生较大波动。\n- 实现失效转移功能，在某台服务器执行完毕后主动抓取未分配的分片，并且在某台服务器下线后主动寻找可用的服务器执行任务。\n\n### 注册中心数据结构\n\n注册中心在定义的命名空间下，创建作业名称节点，用于区分不同作业，所以作业一旦创建则不能修改作业名称，如果修改名称将视为新的作业。\n作业名称节点下又包含5个数据子节点，分别是 config, instances, sharding, servers 和 leader。\n\n### config 节点\n\n作业配置信息，以 YAML 格式存储。\n\n### instances 节点\n\n作业运行实例信息，子节点是当前作业运行实例的主键。\n作业运行实例主键由作业运行服务器的 IP 地址和 PID 构成。\n作业运行实例主键均为临时节点，当作业实例上线时注册，下线时自动清理。注册中心监控这些节点的变化来协调分布式作业的分片以及高可用。\n可在作业运行实例节点写入 TRIGGER 表示该实例立即执行一次。\n\n### sharding 节点\n\n作业分片信息，子节点是分片项序号，从零开始，至分片总数减一。\n分片项序号的子节点存储详细信息。每个分片项下的子节点用于控制和记录分片运行状态。\n节点详细信息说明：\n\n| 子节点名     | 临时节点 | 描述                                          |\n|----------|:-----|:--------------------------------------------|\n| instance | 否    | 执行该分片项的作业运行实例主键                             |\n| running  | 是    | 分片项正在运行的状态<br />仅配置 monitorExecution 时有效    |\n| failover | 是    | 如果该分片项被失效转移分配给其他作业服务器，则此节点值记录执行此分片的作业服务器 IP |\n| misfire  | 否    | 是否开启错过任务重新执行                                |\n| disabled | 否    | 是否禁用此分片项                                    |\n\n### servers 节点\n\n作业服务器信息，子节点是作业服务器的 IP 地址。\n可在 IP 地址节点写入 DISABLED 表示该服务器禁用。\n在新的云原生架构下，servers 节点大幅弱化，仅包含控制服务器是否可以禁用这一功能。\n为了更加纯粹的实现作业核心，servers 功能未来可能删除，控制服务器是否禁用的能力应该下放至自动化部署系统。\n\n### leader 节点\n\n作业服务器主节点信息，分为 election，sharding 和 failover 三个子节点。\n分别用于主节点选举，分片和失效转移处理。\n\nleader节点是内部使用的节点，如果对作业框架原理不感兴趣，可不关注此节点。\n\n| 子节点名                 | 临时节点 | 描述                                                                                                              |\n|----------------------|:-----|:----------------------------------------------------------------------------------------------------------------|\n| election\\instance    | 是    | 主节点服务器IP地址<br />一旦该节点被删除将会触发重新选举<br />重新选举的过程中一切主节点相关的操作都将阻塞                                                    |\n| election\\latch       | 否    | 主节点选举的分布式锁<br />为 curator 的分布式锁使用                                                                               |\n| sharding\\necessary   | 否    | 是否需要重新分片的标记<br />如果分片总数变化，或作业服务器节点上下线或启用/禁用，以及主节点选举，会触发设置重分片标记<br />作业在下次执行时使用主节点重新分片，且中间不会被打断<br />作业执行时不会触发分片 |\n| sharding\\processing  | 是    | 主节点在分片时持有的节点<br />如果有此节点，所有的作业执行都将阻塞，直至分片结束<br />主节点分片结束或主节点崩溃会删除此临时节点                                          |\n| failover\\items\\分片项   | 否    | 一旦有作业崩溃，则会向此节点记录<br />当有空闲作业服务器时，会从此节点抓取需失效转移的作业项                                                               |\n| failover\\items\\latch | 否    | 分配失效转移分片项时占用的分布式锁<br />为 curator 的分布式锁使用                                                                        |\n\n### 流程图\n\n#### 作业启动\n\n![作业启动](https://shardingsphere.apache.org/elasticjob/current/img/principles/job_start.jpg)\n\n#### 作业执行\n\n![作业执行](https://shardingsphere.apache.org/elasticjob/current/img/principles/job_exec.jpg)\n"
  },
  {
    "path": "docs/content/features/elastic.en.md",
    "content": "+++\npre = \"<b>3.2. </b>\"\ntitle = \"Elastic Schedule\"\nweight = 2\nchapter = true\n+++\n\nElastic schedule is the most important feature in ElasticJob, which acts as a job processing system that enables the horizontal scaling of jobs by sharding, it's also the origin of the project name \"ElasticJob\".\n\n## Sharding\n\nA concept in ElasticJob to split the job, enabling the job to be executed in distributed environment, where every single server only executes one of the slice that is assigned to it.\nElasticJob is aware of the number of servers in an almost-real-time manner, with the increment/decrement number of the servers, it re-assigns the job slices to the distributed servers, maximizing the efficiency as the increment of resources.\n\nTo execute the job in distributed servers, a job will be divided into multiple individual job items, one or some of which will be executed by the distributed servers.\n\nFor example, if a job is divided into 4 slices, and there are two servers to execute the job, then each server is assigned 2 slices, undertaking 50% of the workload, as follows.\n\n![Sharding Job](https://shardingsphere.apache.org/elasticjob/current/img/elastic/sharding.png)\n\n### Sharding Item\n\nElasticJob doesn't directly provide the abilities to process the data, instead, it assigns the sharding items to the job servers, where the developers should process the sharding items and their business logic themselves.\nThe sharding item is numeric type, in the range of [0, size(slices) - 1].\n\n### Customized sharding options\n\nCustomized sharding options can build a relationship with the sharding items, converting the sharding items' numbers to more readable business codes.\n\nFor example, to horizontally split the databases according to the regions, database A stores data from Beijing, database B stores data from Shanghai and database C stores data from Guangzhou.\nIf we configure only by the sharding items' numbers, the developers need the knowledge that 0 represents Beijing, 1 represents Shanghai and 2 represents Guangzhou.\nCustomized sharding options make the codes more readable, if we have customized options `0=Beijing,1=Shanghai,2=Guangzhou`, we can simply use `Beijing`, `Shanghai`, `Guangzhou` in the codes.\n\n## Maximize the usage of resources\n\nElasticJob provides a flexible way to maximize the throughput of the jobs.\nWhen new job server joins, ElasticJob will be aware of it from the registry, and will re-shard in the next scheduling process, the new server will undertake some of the job slices, as follows.\n\n![scale out](https://shardingsphere.apache.org/elasticjob/current/img/elastic/sacle-out.png)\n\nConfiguring a larger number of sharding items than the number of servers, or better, a multiplier of the number of servers, makes it more reasonably for the job to leverage the resources, and assign the sharding items dynamically.\n\nFor example, we have 10 sharding items and there are 3 servers, the number of sharding items are server A = 0,1,2,9; server B = 3,4,5; server C = 6,7,8.\nIf the server C is down, then server A = 0,1,2,3,4 and B = 5,6,7,8,9, maximizing the throughput without losing any sharding item.\n\n## High Availability\n\nWhen a server is down when executing a sharding item, the registry is also aware of that, and the sharding item will be transferred to another living server, thus achieve the goal of high availability.\nThe unfinished job from a crashed server will be transferred and executed continuously, as follows.\n\n![HA](https://shardingsphere.apache.org/elasticjob/current/img/elastic/ha.png)\n\nSetting the total number of sharding items to 1 and more than 1 servers to execute the jobs makes the job run in the mode of `1` master and `n` slaves.\nOnce the servers that are executing jobs are down, the idle servers will take over the jobs and execute them in the next scheduling, or better, if the failover option is enabled, the idle servers can take over the failed jobs immediately.\n\n## Implementation Principle\n\nElasticJob does not have a job scheduling center node, but the programs based on the deployment job framework trigger the scheduling when the corresponding time point is reached.\nThe registration center is only used for job registration and monitoring information storage. The main job node is only used to handle functions such as sharding and cleaning.\n\n### Elastic Distributed Implementation\n\n- The first server went online to trigger the main server election. Once the main server goes offline, the election is triggered again, and the election process is blocked. Only when the main server election is completed, other tasks will be performed.\n- When a job server goes online, it will automatically register the server information to the registry, and automatically update the server status when it goes offline.\n- The re-sharding flag will be updated when the master node is elected, the server goes offline, and the total number of shards changes.\n- When a scheduled task is triggered, if it needs to be sharded again, it will be sharded by the main server. The sharding process is blocked, and the task can be executed after the sharding ends.\n If the main server goes offline during the sharding process, the master server will be elected first and then perform sharding.\n- From the previous description, in order to maintain the stability of the job runtime, only the sharding status will be marked during the running process, and the sharding will not be re-sharded. Sharding can only occur before the next task is triggered.\n- Each execution of sharding will sort instances by server IP to ensure that the sharding result will not produce large fluctuations.\n- Realize the failover function, actively grab the unallocated shards after a certain server is executed, and actively search for available servers to perform tasks after a certain server goes offline.\n\n### Registry Data Structure\n\nThe registration center creates a job name node under the defined namespace to distinguish different jobs, so once a job is created, the job name cannot be modified. If the name is modified, it will be regarded as a new job. \nThere are 5 data sub-nodes under the job name node, namely config, instances, sharding, servers and leader.\n\n### config node\n\nJob configuration information, stored in YAML format.\n\n### instances node\n\nJob running instance information, the child node is the primary key of the current job running instance.\nThe primary key of the job running instance is composed of the IP address and PID of the job running server.\nThe primary keys of the job running instance are all ephemeral nodes, which are registered when the job instance is online and automatically cleaned up when the job instance is offline. The registry monitors the changes of these nodes to coordinate the sharding and high availability of distributed jobs.\nYou can write TRIGGER in the job running instance node to indicate that the instance will be executed once immediately.\n\n### sharding node\n\nJob sharding information. The child node is the sharding item sequence number, starting from zero and ending with the total number of shards minus one.\nThe child node of the sharding item sequence number stores detailed information. The child node under each shard is used to control and record the running status of the shard.\nNode details description：\n\n| Child node name | Ephemeral node | Description                                                                                                                        |\n|-----------------|:---------------|:-----------------------------------------------------------------------------------------------------------------------------------|\n| instance        | NO             | The primary key of the job running instance that executes the shard                                                                |\n| running         | YES            | The running state of the shard item.<br/>Only valid when monitorExecution is configured                                            |\n| failover        | YES            | If the shard item is assigned to another job server by failover, this node value records the job server IP that executes the shard |\n| misfire         | NO             | Whether to restart the missed task                                                                                                 |\n| disabled        | NO             | Whether to disable this shard                                                                                                      |\n\n### servers node\n\nJob server information, the child node is the IP address of the job server.\nYou can write DISABLED in the IP address node to indicate that the server is disabled.\nUnder the new cloud-native architecture, the servers node is greatly weakened, only including controlling whether the server can be disabled.\nIn order to achieve the core of the job more purely, the server function may be deleted in the future, and the ability to control whether the server is disabled should be delegated to the automated deployment system.\n\n### leader node\n\nThe master node information of the job server is divided into three sub-nodes: election, sharding and failover.\nThey are used for master node election, sharding and failover processing respectively.\n\nThe leader node is an internally used node. If you are not interested in the principle of the job framework, you don't need to pay attention to this node.\n\n| Child node name           | Ephemeral node | Description                                                                                                                                                                                                                                                                                                                                            |\n|---------------------------|:---------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| election\\instance         | YES            | The IP address of the master node server.<br />Once the node is deleted, a re-election will be triggered.<br />All operations related to the master node will be blocked during the re-election process.                                                                                                                                               |\n| election\\latch            | NO             | Distributed locks elected by the master node<br />Used for distributed locks of curator                                                                                                                                                                                                                                                                |\n| sharding\\necessary        | NO             | The flag for re-sharding. If the total number of shards changes, or the job server node goes online or offline or enabled/disabled, as well as the master node election, the re-sharded flag will be triggered. The master node is re-sharded without being interrupted in the middle<br />The sharding will not be triggered when the job is executed |\n| sharding\\processing       | YES            | The node held by the master node during sharding.<br />If there is this node, all job execution will be blocked until the sharding ends.<br />The ephemeral node will be deleted when the master node sharding is over or the master node crashes                                                                                                      |\n| failover\\items\\shard item | NO             | Once a job crashes, it will record to this node.<br />When there is an idle job server, it will grab the job items that need to failover from this node                                                                                                                                                                                                |\n| failover\\items\\latch      | NO             | Distributed locks used when allocating failover shard items.<br /> Used by curator distributed locks                                                                                                                                                                                                                                                   |\n"
  },
  {
    "path": "docs/content/features/failover.cn.md",
    "content": "+++\npre = \"<b>3.4. </b>\"\ntitle = \"失效转移\"\nweight = 4\nchapter = true\n+++\n\nElasticJob 不会在本次执行过程中进行重新分片，而是等待下次调度之前才开启重新分片流程。\n当作业执行过程中服务器宕机，失效转移允许将该次未完成的任务在另一作业节点上补偿执行。\n\n## 概念\n\n失效转移是当前执行作业的临时补偿执行机制，在下次作业运行时，会通过重分片对当前作业分配进行调整。\n举例说明，若作业以每小时为间隔执行，每次执行耗时 30 分钟。如下如图所示。\n\n![定时作业](https://shardingsphere.apache.org/elasticjob/current/img/failover/job.png)\n\n图中表示作业分别于 12:00，13:00 和 14:00 执行。图中显示的当前时间点为 13:00 的作业执行中。\n\n如果作业的其中一个分片服务器在 13:10 的时候宕机，那么剩余的 20 分钟应该处理的业务未得到执行，并且需要在 14:00 时才能再次开始执行下一次作业。\n也就是说，在不开启失效转移的情况下，位于该分片的作业有 50 分钟空档期。如下如图所示。\n\n![作业宕机](https://shardingsphere.apache.org/elasticjob/current/img/failover/job-crash.png)\n\n在开启失效转移功能之后，ElasticJob 的其他服务器能够在感知到宕机的作业服务器之后，补偿执行该分片作业。如下图所示。\n\n![补偿执行](https://shardingsphere.apache.org/elasticjob/current/img/failover/job-failover.png)\n\n在资源充足的情况下，作业仍然能够在 13:30 完成执行。\n\n## 执行机制\n\n当作业执行节点宕机时，会触发失效转移流程。ElasticJob 根据触发时的分布式作业执行的不同状况来决定失效转移的执行时机。\n\n### 通知执行\n\n当其他服务器感知到有失效转移的作业需要处理时，且该作业服务器已经完成了本次任务，则会实时的拉取待失效转移的分片项，并开始补偿执行。\n也称为实时执行。\n\n### 问询执行\n\n作业服务在本次任务执行结束后，会向注册中心问询待执行的失效转移分片项，如果有，则开始补偿执行。\n也称为异步执行。\n\n## 适用场景\n\n开启失效转移功能，ElasticJob 会监控作业每一分片的执行状态，并将其写入注册中心，供其他节点感知。\n\n在一次运行耗时较长且间隔较长的作业场景，失效转移是提升作业运行实时性的有效手段；\n对于间隔较短的作业，会产生大量与注册中心的网络通信，对集群的性能产生影响。\n而且间隔较短的作业并未见得关注单次作业的实时性，可以通过下次作业执行的重分片使所有的分片正确执行，因此不建议短间隔作业开启失效转移。\n\n另外需要注意的是，作业本身的幂等性，是保证失效转移正确性的前提。\n"
  },
  {
    "path": "docs/content/features/failover.en.md",
    "content": "+++\npre = \"<b>3.4. </b>\"\ntitle = \"Failover\"\nweight = 4\nchapter = true\n+++\n\nElasticJob will not re-shard during this execution, but wait for the next scheduling before starting the re-sharding process.\nWhen the server is down during job execution, failover allows the unfinished task to be compensated and executed on another job node.\n\n## Concept\n\nFailover is a temporary compensation execution mechanism for the currently executed job. When the next job is run, the current job allocation will be adjusted through resharding.\nFor example, if the job is executed at an hourly interval, each execution will take 30 minutes. As shown below.\n\n![Job](https://shardingsphere.apache.org/elasticjob/current/img/failover/job.png)\n\nThe figure shows that the jobs are executed at 12:00, 13:00 and 14:00 respectively. The current time point shown in the figure is the job execution at 13:00.\n\nIf one of the shard servers of the job goes down at 13:10, the remaining 20 minutes of the business that should be processed are not executed, and the next job can only be executed at 14:00.\nIn other words, if failover is not turned on, there is a 50-minute idle period in this shard. As shown below.\n\n![Job Crash](https://shardingsphere.apache.org/elasticjob/current/img/failover/job-crash.png)\n\nAfter the failover is enabled, other ElasticJob servers can compensate for the execution of the sharding job after sensing the down job server. As shown below.\n\n![Job Failover](https://shardingsphere.apache.org/elasticjob/current/img/failover/job-failover.png)\n\nWith sufficient resources, the job can still be executed completely at 13:30.\n\n## Execution mechanism\n\nWhen the job execution node goes down, the failover process will be triggered. ElasticJob determines the execution timing of the failover according to the different conditions of the distributed job execution when it is triggered。\n\n### Notification execution\n\nWhen other servers perceive that a failover job needs to be processed, and the job server has completed this task, it will pull the items to be failed over in real time and start compensation execution.\nAlso called real-time execution.\n\n### Enquiry execution\n\nAfter the execution of this task, the job service will inquire about the failover items to be executed from the registry, and if there are any, the compensation execution will start.\nAlso called asynchronous execution.\n\n## Scenarios:\n\nWith the failover enabled, ElasticJob will monitor the execution status of each shard of the job and write it to the registry for other nodes to perceive.\n\nIn a job scenario that takes a long time to run and has a long interval, failover is an effective means to improve the real-time operation of the job;\nFor short-interval jobs, a large number of network communications with the registry will be generated, which will affect the performance of the cluster;\nMoreover, short-interval jobs do not necessarily pay attention to the real-time performance of a single job. You can use the re-shard of the next job execution to make all the items execute correctly. Therefore, it is not recommended to enable failover for short-interval jobs.\n\nAnother thing to note is that the idempotence of the job itself is a prerequisite to ensure the correctness of failover.\n\n"
  },
  {
    "path": "docs/content/features/job-type.cn.md",
    "content": "+++\npre = \"<b>3.6. </b>\"\ntitle = \"作业开放生态\"\nweight = 6\nchapter = true\n+++\n\n灵活定制化作业是 ElasticJob 3.x 版本的最重要设计变革。\n新版本基于 Apache ShardingSphere 可插拔架构的设计理念，打造了全新作业 API。\n意在使开发者能够更加便捷且相互隔离的方式拓展作业类型，打造 ElasticJob 作业的生态圈。\n\nElasticJob 提供了对作业的弹性伸缩、分布式治理等功能的同时，并未限定作业的类型。\n它通过灵活的作业 API，将作业解耦为作业接口和执行器接口。\n用户可以定制化全新的作业类型，诸如脚本执行、HTTP 服务执行（3.0.0-beta 提供）、大数据类作业、文件类作业等。\n目前 ElasticJob 内置了简单作业、数据流作业和脚本执行作业，并且完全开放了扩展接口，开发者可以通过 SPI 的方式引入新的作业类型，并且可以便捷的回馈至社区。\n\n## 作业接口\n\nElasticJob 的作业可划分为基于 class 类型和基于 type 类型两种。\n\nClass 类型的作业由开发者直接使用，需要由开发者实现该作业接口实现业务逻辑。典型代表：Simple 类型、Dataflow 类型。\nType 类型的作业只需提供类型名称即可，开发者无需实现该作业接口，而是通过外置配置的方式使用。典型代表：Script 类型、HTTP 类型。\n\n## 执行器接口\n\n用于执行用户定义的作业接口，通过 Java 的 SPI 机制织入 ElasticJob生态。\n"
  },
  {
    "path": "docs/content/features/job-type.en.md",
    "content": "+++\npre = \"<b>3.6. </b>\"\ntitle = \"Job Open Ecosystem\"\nweight = 6\nchapter = true\n+++\n\nFlexible customized jobs is the most important design change in ElasticJob 3.x .\nThe new version is based on the design concept of the Apache ShardingSphere pluggable architecture, and the new Job API was created.\nIt is intended to enable developers to expand the types of jobs in a more convenient and isolated way, and create an ecosystem of ElasticJob jobs.\n\nWhile ElasticJob provides functions such as elastic scaling and distributed management of jobs, it does not limit the types of jobs.\nIt uses flexible job APIs to decouple jobs into job interfaces and actuator interfaces.\nUsers can customize new job types, such as script execution, HTTP service execution, big data jobs, file jobs, etc.\nAt present, ElasticJob has built-in simple jobs, data flow jobs, and script execution jobs, and has completely opened up the extension interface. Developers can introduce new job types through SPI, and they can easily give back to the community.\n\n## Job interface\n\nElasticJob jobs can be divided into two types: `Class-based Jobs` and `Type-based Jobs`.\n\n`Class-based Jobs` are directly used by developers, who need to implement the job interface to realize business logic. Typical representatives: Simple type, Dataflow type.\n`Type-based Jobs` only need to provide the type name, developers do not need to implement the job interface, but use it through external configuration. Typical representatives: Script type, HTTP type (Since 3.0.0-beta).\n\n## Actuator interface\n\nIt is used to execute user-defined job interfaces and weave into the ElasticJob ecosystem through Java's SPI mechanism.\n"
  },
  {
    "path": "docs/content/features/misfire.cn.md",
    "content": "+++\npre = \"<b>3.5. </b>\"\ntitle = \"错过任务重执行\"\nweight = 5\nchapter = true\n+++\n\nElasticJob 不允许作业在同一时间内叠加执行。\n当作业的执行时长超过其运行间隔，错过任务重执行能够保证作业在完成上次的任务后继续执行逾期的作业。\n\n## 概念\n\n错过任务重执行功能可以使逾期未执行的作业在之前作业执行完成之后立即执行。\n举例说明，若作业以每小时为间隔执行，每次执行耗时 30 分钟。如下如图所示。\n\n![定时作业](https://shardingsphere.apache.org/elasticjob/current/img/misfire/job.png)\n\n图中表示作业分别于 12:00，13:00 和 14:00 执行。图中显示的当前时间点为 13:00 的作业执行中。\n\n如果 12：00 开始执行的作业在 13:10 才执行完毕，那么本该由 13:00 触发的作业则错过了触发时间，需要等待至 14:00 的下次作业触发。\n如下如图所示。\n\n![错过作业](https://shardingsphere.apache.org/elasticjob/current/img/misfire/job-missed.png)\n\n在开启错过任务重执行功能之后，ElasticJob 将会在上次作业执行完毕后，立刻触发执行错过的作业。如下图所示。\n\n![错过作业重执行](https://shardingsphere.apache.org/elasticjob/current/img/misfire/job-misfire.png)\n\n在 13：00 和 14:00 之间错过的作业将会重新执行。 \n\n## 适用场景\n\n在一次运行耗时较长且间隔较长的作业场景，错过任务重执行是提升作业运行实时性的有效手段；\n对于未见得关注单次作业的实时性的短间隔的作业来说，开启错过任务重执行并无必要。\n"
  },
  {
    "path": "docs/content/features/misfire.en.md",
    "content": "+++\npre = \"<b>3.5. </b>\"\ntitle = \"Misfire\"\nweight = 5\nchapter = true\n+++\n\nElasticJob does not allow jobs to be executed at the same time.\nWhen the execution time of a job exceeds its running interval, re-executing the missed task can ensure that the job continues to execute the overdue job after completing the last task.\n\n## Concept\n\nThe misfire function enables the overdue tasks to be executed immediately after the completion of the previous tasks.\nFor example, if the job is executed at an hourly interval, each execution will take 30 minutes. As shown below.\n\n![Job](https://shardingsphere.apache.org/elasticjob/current/img/misfire/job.png)\n\nThe figure shows that the jobs are executed at 12:00, 13:00 and 14:00 respectively. The current time point shown in the figure is the job execution at 13:00.\n\nIf the job executed at 12:00 is finished at 13:10, then the job that should have been triggered by 13:00 missed the trigger time and needs to wait until the next job trigger at 14:00. As shown below.\n\n![Job Missed](https://shardingsphere.apache.org/elasticjob/current/img/misfire/job-missed.png)\n\nAfter the misfire is enabled, ElasticJob will trigger the execution of the missed job immediately after the last job is executed. As shown below.\n\n![Job Misfire](https://shardingsphere.apache.org/elasticjob/current/img/misfire/job-misfire.png)\n\nMissed jobs between 13:00 and 14:00 will be executed again.\n\n## Scenarios\n\nIn a job scenario that takes a long time to run and has a long interval, misfire is an effective means to improve the real-time operation of the job;\nFor short-interval jobs that do not necessarily pay attention to the real-time performance of a single job, it is not necessary to turn on the misfire to re-execute.\n"
  },
  {
    "path": "docs/content/features/schedule-model.cn.md",
    "content": "+++\npre = \"<b>3.1. </b>\"\ntitle = \"调度模型\"\nweight = 1\nchapter = true\n+++\n\nElasticJob 是面向进程内的线程级调度框架。通过它，作业能够透明化的与业务应用系统相结合。\n它能够方便的与 Spring 、Dubbo 等 Java 框架配合使用，在作业中可自由使用 Spring 注入的 Bean，如数据源连接池、Dubbo 远程服务等，更加方便的贴合业务开发。\n"
  },
  {
    "path": "docs/content/features/schedule-model.en.md",
    "content": "+++\npre = \"<b>3.1. </b>\"\ntitle = \"Schedule Model\"\nweight = 1\nchapter = true\n+++\n\nElasticJob is a thread-level scheduling framework for in-process.\nThrough it, Job can be transparently combined with business application systems.\nIt can be easily used in conjunction with Java frameworks such as Spring and Dubbo.\nSpring DI (Dependency Injection) Beans can be freely used in Job, such as data source connection pool and Dubbo remote service, etc., which is more convenient for business development.\n"
  },
  {
    "path": "docs/content/overview/_index.cn.md",
    "content": "+++\npre = \"<b>1. </b>\"\ntitle = \"概览\"\nweight = 1\nchapter = true\n+++\n\n[![GitHub release](https://img.shields.io/github/release/apache/shardingsphere-elasticjob.svg?style=social&label=Release)](https://github.com/apache/shardingsphere-elasticjob/releases)&nbsp;\n[![GitHub stars](https://img.shields.io/github/stars/apache/shardingsphere-elasticjob.svg?style=social&label=Star)](https://github.com/apache/shardingsphere-elasticjob/stargazers)&nbsp;\n[![GitHub forks](https://img.shields.io/github/forks/apache/shardingsphere-elasticjob.svg?style=social&label=Fork)](https://github.com/apache/shardingsphere-elasticjob/fork)&nbsp;\n[![GitHub watchers](https://img.shields.io/github/watchers/apache/shardingsphere-elasticjob.svg?style=social&label=Watch)](https://github.com/apache/shardingsphere-elasticjob/watchers)\n[![Stargazers over time](https://starchart.cc/apache/shardingsphere-elasticjob.svg)](https://starchart.cc/apache/shardingsphere-elasticjob)\n\nElasticJob 通过弹性调度、资源管控、以及作业治理的功能，打造一个适用于互联网场景的分布式调度解决方案，并通过开放的架构设计，提供多元化的作业生态。\n它的各个产品使用统一的作业 API，开发者仅需一次开发，即可随意部署。\n\nElasticJob 已于 2020 年 5 月 28 日成为 [Apache ShardingSphere](https://shardingsphere.apache.org/) 的子项目。\n欢迎通过[邮件列表](mailto:dev@shardingsphere.apache.org)参与讨论。\n\n[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)\n\n[![GitHub release](https://img.shields.io/github/release/apache/shardingsphere-elasticjob.svg)](https://github.com/apache/shardingsphere-elasticjob/releases)\n\n[![Maven Status](https://maven-badges.herokuapp.com/maven-central/org.apache.shardingsphere.elasticjob/elasticjob/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.apache.shardingsphere.elasticjob/elasticjob)\n[![Build Status](https://secure.travis-ci.org/apache/shardingsphere-elasticjob.png?branch=master)](https://travis-ci.org/apache/shardingsphere-elasticjob)\n[![Coverage Status](https://coveralls.io/repos/github/apache/shardingsphere-elasticjob/badge.svg?branch=master)](https://coveralls.io/github/apache/shardingsphere-elasticjob?branch=master)\n\n## 简介\n\n使用 ElasticJob 能够让开发工程师不再担心任务的线性吞吐量提升等非功能需求，使他们能够更加专注于面向业务编码设计；\n同时，它也能够解放运维工程师，使他们不必再担心任务的可用性和相关管理需求，只通过轻松的增加服务节点即可达到自动化运维的目的。\n\nElasticJob 定位为轻量级无中心化解决方案，使用 jar 的形式提供分布式任务的协调服务。\n\n![ElasticJob Architecture](https://shardingsphere.apache.org/elasticjob/current/img/architecture/elasticjob_lite.png)\n\n## 功能列表\n\n- 弹性调度\n  - 支持任务在分布式场景下的分片和高可用\n  - 能够水平扩展任务的吞吐量和执行效率\n  - 任务处理能力随资源配备弹性伸缩\n\n- 资源分配\n  - 在适合的时间将适合的资源分配给任务并使其生效\n  - 相同任务聚合至相同的执行器统一处理\n  - 动态调配追加资源至新分配的任务\n\n- 作业治理\n  - 失效转移\n  - 错过作业重新执行\n  - 自诊断修复\n\n- 作业依赖(TODO)\n  - 基于有向无环图（DAG）的作业间依赖\n  - 基于有向无环图（DAG）的作业分片间依赖\n\n- 作业开放生态\n  - 可扩展的作业类型统一接口\n  - 丰富的作业类型库，如数据流、脚本、HTTP、文件、大数据等\n  - 易于对接业务作业，能够与 Spring 依赖注入无缝整合\n\n- 可视化管控端\n  - 作业管控端\n  - 作业执行历史数据追踪\n  - 注册中心管理\n\n## 环境要求\n\n### Java\n\n请使用 Java 8 及其以上版本。\n\n### Maven\n\n请使用 Maven 3.5.0 及其以上版本。\n\n### ZooKeeper\n\n请使用 ZooKeeper 3.6.0 及其以上版本。[详情参见](https://zookeeper.apache.org/)\n"
  },
  {
    "path": "docs/content/overview/_index.en.md",
    "content": "+++\npre = \"<b>1. </b>\"\ntitle = \"Overview\"\nweight = 1\nchapter = true\n+++\n\n[![GitHub release](https://img.shields.io/github/release/apache/shardingsphere-elasticjob.svg?style=social&label=Release)](https://github.com/apache/shardingsphere-elasticjob/releases)&nbsp;\n[![GitHub stars](https://img.shields.io/github/stars/apache/shardingsphere-elasticjob.svg?style=social&label=Star)](https://github.com/apache/shardingsphere-elasticjob/stargazers)&nbsp;\n[![GitHub forks](https://img.shields.io/github/forks/apache/shardingsphere-elasticjob.svg?style=social&label=Fork)](https://github.com/apache/shardingsphere-elasticjob/fork)&nbsp;\n[![GitHub watchers](https://img.shields.io/github/watchers/apache/shardingsphere-elasticjob.svg?style=social&label=Watch)](https://github.com/apache/shardingsphere-elasticjob/watchers)\n[![Stargazers over time](https://starchart.cc/apache/shardingsphere-elasticjob.svg)](https://starchart.cc/apache/shardingsphere-elasticjob)\n\nThrough the functions of flexible scheduling, resource management and job management, \nit creates a distributed scheduling solution suitable for Internet scenarios, \nand provides a diversified job ecosystem through open architecture design.\nIt uses a unified job API for each project.\nDevelopers only need code one time and can deploy at will.\n\nElasticJob became an [Apache ShardingSphere](https://shardingsphere.apache.org/) Sub project on May 28 2020.\n\nWelcome communicate with community via [mail list](mailto:dev@shardingsphere.apache.org).\n\n[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)\n\n[![GitHub release](https://img.shields.io/github/release/apache/shardingsphere-elasticjob.svg)](https://github.com/apache/shardingsphere-elasticjob/releases)\n\n[![Maven Status](https://maven-badges.herokuapp.com/maven-central/org.apache.shardingsphere.elasticjob/elasticjob/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.apache.shardingsphere.elasticjob/elasticjob)\n[![Build Status](https://secure.travis-ci.org/apache/shardingsphere-elasticjob.png?branch=master)](https://travis-ci.org/apache/shardingsphere-elasticjob)\n[![Coverage Status](https://coveralls.io/repos/github/apache/shardingsphere-elasticjob/badge.svg?branch=master)](https://coveralls.io/github/apache/shardingsphere-elasticjob?branch=master)\n\n## Introduction\n\nUsing ElasticJob can make developers no longer worry about the non-functional requirements such as jobs scale out, so that they can focus more on business coding;\nAt the same time, it can release operators too, so that they do not have to worry about jobs high availability and management, and can automatic operation by simply adding servers.\n\nElasticJob is a lightweight, decentralized solution that provides distributed task sharding services.\n\n![ElasticJob Architecture](https://shardingsphere.apache.org/elasticjob/current/img/architecture/elasticjob_lite.png)\n\n## Features\n\n- Elastic Schedule\n  - Support job sharding and high availability in distributed system\n  - Scale out for throughput and efficiency improvement\n  - Job processing capacity is flexible and scalable with the allocation of resources\n\n- Resource Assign\n  - Execute job on suitable time and assigned resources\n  - Aggregation same job to same job executor\n  - Append resources to newly assigned jobs dynamically\n\n- Job Governance\n  - Failover\n  - Misfired\n  - Self diagnose and recover when distribute environment unstable\n\n- Job Dependency (TODO)\n  - DAG based job dependency\n  - DAG based job item dependency\n\n- Job Open Ecosystem\n  - Unify job api for extension\n  - Support rich job type lib, such as dataflow, script, HTTP, file, big data\n  - Focus business SDK, can work with Spring IOC\n\n- Admin Console\n  - Job administration\n  - Job event trace query\n  - Registry center management\n\n## Environment Required\n\n### Java\n\nJava 8 or above required.\n\n### Maven\n\nMaven 3.5.0 or above required.\n\n### ZooKeeper\n\nZooKeeper 3.6.0 or above required. [See details](https://zookeeper.apache.org/)\n"
  },
  {
    "path": "docs/content/powered-by/_index.cn.md",
    "content": "+++\npre = \"<b>7. </b>\"\ntitle = \"采用公司\"\nweight = 7\nchapter = true\n+++\n\n## 登记\n\n欢迎采用了 ElasticJob 的公司在此登记，您的支持是我们最大的动力。\n\n请按`公司名` + `首页` + `应用案例（可选）` 的格式在[此处](https://github.com/apache/shardingsphere-elasticjob/issues/254)登记。\n\n## 谁在使用 ElasticJob?\n\n共计 83 家公司。\n\n### 电子商务\n<ul>\n   <li><a href=\"http://www.dangdang.com/\" rel=\"nofollow\">当当</a></li>\n    <li><a href=\"http://www.3songshu.com/\" rel=\"nofollow\">三只松鼠</a></li>\n    <li><a href=\"http://www.bessky.cn/\" rel=\"nofollow\">宝视佳</a></li>\n    <li><a href=\"https://www.haizol.com/\" rel=\"nofollow\">海智在线</a></li>\n    <li><a href=\"http://www.xiu.com/\" rel=\"nofollow\">走秀网</a></li>\n    <li><a href=\"https://www.homedo.com/\" rel=\"nofollow\">河姆渡</a></li>\n    <li><a href=\"http://www.eavic.com/\" rel=\"nofollow\">中航电子采购平台</a></li>\n    <li><a href=\"http://www.b5cai.com/\" rel=\"nofollow\">帮5采</a></li>\n    <li><a href=\"https://www.chunbo.com/\" rel=\"nofollow\">春播</a></li>\n    <li><a href=\"https://www.cnhnb.com/\" rel=\"nofollow\">惠农网</a></li>\n    <li><a href=\"https://www.dazong.com/\" rel=\"nofollow\">飞马大宗</a></li>\n    <li><a href=\"https://www.yunyangtao.com/\" rel=\"nofollow\">洋桃跨境供应链</a></li>\n    <li><a href=\"https://www.dg-mall.com/\" rel=\"nofollow\">点购集团</a></li>\n    <li><a href=\"https://nexposter.com/\" rel=\"nofollow\">晶泓科技</a></li>\n    <li><a href=\"https://www.jd.com/\" rel=\"nofollow\">京东</a></li>\n</ul>\n\n### 金融行业\n<ul>\n    <li><a href=\"https://www.bestpay.com.cn/\" rel=\"nofollow\">甜橙金融(翼支付)</a></li>\n    <li><a href=\"http://www.wxsbank.com/\" rel=\"nofollow\">无锡锡商银行</a></li>\n    <li><a href=\"https://www.ppdai.com/\" rel=\"nofollow\">拍拍贷</a></li>\n    <li><a href=\"https://www.ysepay.com/\" rel=\"nofollow\">银盛支付</a></li>\n    <li><a href=\"https://www.zhongan.com/\" rel=\"nofollow\">众安保险</a></li>\n    <li><a href=\"http://www.jchl.com/\" rel=\"nofollow\">金财互联</a></li>\n    <li><a href=\"https://www.lianlianpay.com/\" rel=\"nofollow\">连连支付</a></li>\n    <li><a href=\"http://www.yaolaivip.com/\" rel=\"nofollow\">耀莱在线</a></li>\n    <li><a href=\"http://www.icinfo.cn/\" rel=\"nofollow\">浙江汇信科技</a></li>\n    <li><a href=\"https://www.laocaibao.com/\" rel=\"nofollow\">捞财宝</a></li>\n    <li><a href=\"https://www.kaniu.com/\" rel=\"nofollow\">卡牛信用管家</a></li>\n    <li><a href=\"http://www.jiedaibao.com/\" rel=\"nofollow\">借贷宝</a></li>\n    <li><a href=\"https://www.jinhui365.com/\" rel=\"nofollow\">金汇金融</a></li>\n    <li><a href=\"http://www.91techgroup.com/\" rel=\"nofollow\">91科技集团</a></li>\n</ul>\n\n### 数字化与云服务\n<ul>\n    <li><a href=\"http://www.yunjiacloud.com/\" rel=\"nofollow\">云嘉云计算</a></li>\n    <li><a href=\"https://www.joyowo.com/\" rel=\"nofollow\">金柚网</a></li>\n    <li><a href=\"https://www.treebear.cn/\" rel=\"nofollow\">树熊网络</a></li>\n    <li><a href=\"https://www.szdgri.com/\" rel=\"nofollow\">南方电网深圳数研院</a></li>\n</ul>\n\n### 出行\n<ul>\n    <li><a href=\"http://www.juneyaoair.com/\" rel=\"nofollow\">吉祥航空</a></li>\n    <li><a href=\"https://www.caocaokeji.cn/\" rel=\"nofollow\">曹操出行</a></li>\n    <li><a href=\"https://www.tuhu.cn/\" rel=\"nofollow\">途虎养车</a></li>\n    <li><a href=\"https://www.01zhuanche.com/\" rel=\"nofollow\">首汽约车</a></li>\n    <li><a href=\"https://www.itrip.com/\" rel=\"nofollow\">iTrip爱去</a></li>\n    <li><a href=\"https://www.maihaoche.com/\" rel=\"nofollow\">卖好车</a></li>\n    <li><a href=\"https://www.ttpai.cn/\" rel=\"nofollow\">天天拍车</a></li>\n    <li><a href=\"https://www.didiglobal.com/\" rel=\"nofollow\">滴滴出行</a></li>\n</ul>\n\n### 物流\n<ul>\n    <li><a href=\"http://www.yto.net.cn/\" rel=\"nofollow\">圆通速递</a></li> \n    <li><a href=\"http://www.haoyunhu56.com/\" rel=\"nofollow\">好运虎物流</a></li>\n    <li><a href=\"http://www.dekuncn.com/\" rel=\"nofollow\">德坤物流</a></li>\n</ul>\n\n### 房地产\n<ul>\n    <li><a href=\"http://www.ziroom.com/\" rel=\"nofollow\">自如网</a></li>\n    <li><a href=\"https://www.ucommune.com/\" rel=\"nofollow\">优客工场</a></li>\n    <li><a href=\"https://www.lianjia.com/\" rel=\"nofollow\">链家网</a></li>\n</ul>\n\n### 互联网教育\n<ul>\n    <li><a href=\"https://www.ibeiliao.com/\" rel=\"nofollow\">贝聊科技</a></li>\n    <li><a href=\"http://www.iqihang.com/\" rel=\"nofollow\">爱启航</a></li>\n    <li><a href=\"https://willclass.com/\" rel=\"nofollow\">会通教育</a></li>\n    <li><a href=\"http://www.thinktown.com/\" rel=\"nofollow\">新课堂教育</a></li>\n    <li><a href=\"https://www.genshuixue.com/\" rel=\"nofollow\">跟谁学</a></li>\n    <li><a href=\"https://www.qidianla.com/\" rel=\"nofollow\">起点学院</a></li>\n</ul>\n\n### 互联网文娱\n<ul>\n    <li><a href=\"https://g.10086.cn/\" rel=\"nofollow\">咪咕互娱</a></li>\n    <li><a href=\"https://www.motie.com/\" rel=\"nofollow\">磨铁文学</a></li>\n    <li><a href=\"http://changemax.cn/\" rel=\"nofollow\">松鼠白菜</a></li>\n</ul>\n\n### 新闻资讯\n<ul>\n    <li><a href=\"http://bj.fangjia.com/\" rel=\"nofollow\">房价网</a></li>\n    <li><a href=\"https://auto.ifeng.com/\" rel=\"nofollow\">凤凰汽车</a></li>\n    <li><a href=\"https://www.taoguba.com.cn/\" rel=\"nofollow\">淘股吧</a></li>\n    <li><a href=\"https://www.fanhaoyue.com/\" rel=\"nofollow\">饭好约</a></li>\n    <li><a href=\"https://www.sohu.com/\" rel=\"nofollow\">搜狐网</a></li>\n</ul>\n\n### 通信科技\n<ul>\n    <li><a href=\"https://www.meizu.com/\" rel=\"nofollow\">魅族</a></li>\n    <li><a href=\"https://www.oneplus.com/cn\" rel=\"nofollow\">一加科技</a></li>\n</ul>\n\n### 物联网\n<ul>\n    <li><a href=\"https://thinkiot.lenovo.com/\" rel=\"nofollow\">联想懂的通信</a></li>\n    <li><a href=\"http://www.neoway.com/\" rel=\"nofollow\">有方科技</a></li>\n    <li><a href=\"https://www.gizwits.com/\" rel=\"nofollow\">机智云</a></li>\n    <li><a href=\"http://www.gdyuanpeng.com/\" rel=\"nofollow\">沅朋物联</a></li>\n    <li><a href=\"https://www.g7.com.cn/\" rel=\"nofollow\">汇通天下</a></li>\n    <li><a href=\"http://www.glsx.com.cn/\">广联赛讯</a></li>\n    <li><a href=\"https://sunwuu.com\">商物云</a></li>\n</ul>\n\n### 软件开发及服务\n<ul>\n    <li><a href=\"https://www.ultrapower.com.cn/\" rel=\"nofollow\">神州泰岳</a></li>\n    <li><a href=\"http://www.duiba.com.cn\" rel=\"nofollow\">兑吧</a></li>\n    <li><a href=\"http://www.cig.com.cn/\" rel=\"nofollow\">新意互动</a></li>\n    <li><a href=\"https://cn.yeahmobi.com/\" rel=\"nofollow\">Yeahmobi</a></li>\n    <li><a href=\"http://www.leimingtech.com/\" rel=\"nofollow\">雷铭科技</a></li>\n    <li><a href=\"https://www.zyzc8.com/\" rel=\"nofollow\">众畅网络科技</a></li>\n    <li><a href=\"http://www.deepdraw.cn/\" rel=\"nofollow\">深绘智能</a></li>\n    <li><a href=\"https://www.go-future.cn/\" rel=\"nofollow\">未来信封</a></li>\n    <li><a href=\"http://www.gzcss.net/\" rel=\"nofollow\">广州中软信息技术有限公司</a></li>\n    <li><a href=\"https://www.shb.ltd/\" rel=\"nofollow\">售后宝</a></li>\n</ul>\n\n### 医疗健康\n<ul>\n    <li><a href=\"https://www.hh.global/\" rel=\"nofollow\">健合集团</a></li>\n    <li><a href=\"http://www.yunyichina.cn/\" rel=\"nofollow\">云医科技</a></li>\n    <li><a href=\"https://www.120yibao.com/\" rel=\"nofollow\">壹宝健康</a></li>\n    <li><a href=\"https://www.sytown.cn/\" rel=\"nofollow\">尚一健康</a></li>\n</ul>\n\n### 零售业\n<ul>\n    <li><a href=\"http://www.yonghui.com.cn/\" rel=\"nofollow\">永辉超市</a></li>\n</ul>\n\n### 人工智能\n<ul>\n    <li><a href=\"https://www.deepblueai.com/\" rel=\"nofollow\">深兰科技</a></li>\n</ul>\n\n\n<img src=\"https://shardingsphere.apache.org/community/image/powered-by.png\" width = \"30%\" height = \"30%\" align=\"right\" alt=\"Powered By ShardingSphere\" />\n"
  },
  {
    "path": "docs/content/powered-by/_index.en.md",
    "content": "+++\npre = \"<b>7. </b>\"\ntitle = \"Powered By\"\nweight = 7\nchapter = true\n+++\n\n## Register\n\nWelcome to register by company + homepage + use case(optional), your support is important to us.\n\nPlease register [here](https://github.com/apache/shardingsphere-elasticjob/issues/254) with `company` + `homepage` + `use case(optional)`.\n\n## Who are using ElasticJob?\n\nTotal: 83 companies.\n\n### E-commerce\n<ul>\n    <li><a href=\"http://www.dangdang.com/\" rel=\"nofollow\">DangDang</a></li>\n    <li><a href=\"http://www.3songshu.com/\" rel=\"nofollow\">Three Squirrels</a></li>\n    <li><a href=\"http://www.bessky.cn/\" rel=\"nofollow\">BESSKY</a></li>\n    <li><a href=\"https://www.haizol.com/\" rel=\"nofollow\">HAI ZOL</a></li>\n    <li><a href=\"http://www.xiu.com/\" rel=\"nofollow\">Xiu</a></li>\n    <li><a href=\"https://www.homedo.com/\" rel=\"nofollow\">homedo</a></li>\n    <li><a href=\"http://www.eavic.com/\" rel=\"nofollow\">AVIC B2B ONLINE TRADING OLATRORM</a></li>\n    <li><a href=\"http://www.b5cai.com/\" rel=\"nofollow\">GShopper</a></li>\n    <li><a href=\"https://www.chunbo.com/\" rel=\"nofollow\">ChunBo</a></li>\n    <li><a href=\"https://www.cnhnb.com/\" rel=\"nofollow\">HuiNong</a></li>\n    <li><a href=\"https://www.dazong.com/\" rel=\"nofollow\">DaZong</a></li>\n    <li><a href=\"https://www.yunyangtao.com/\" rel=\"nofollow\">YangSC</a></li>\n    <li><a href=\"https://www.dg-mall.com/\" rel=\"nofollow\">DG-Mail</a></li>\n    <li><a href=\"https://nexposter.com/\" rel=\"nofollow\">Nex Poster</a></li>\n    <li><a href=\"https://www.jd.com/\" rel=\"nofollow\">JD</a></li>\n</ul>\n\n### Financial Industry\n<ul>\n    <li><a href=\"https://www.bestpay.com.cn/\" rel=\"nofollow\">Best Pay</a></li>\n    <li><a href=\"http://www.wxsbank.com/\" rel=\"nofollow\">WX XISHANG BANK</a></li>\n    <li><a href=\"https://www.ppdai.com/\" rel=\"nofollow\">ppdai</a></li>\n    <li><a href=\"https://www.ysepay.com/\" rel=\"nofollow\">YinSheng E-Pay</a></li>\n    <li><a href=\"https://www.zhongan.com/\" rel=\"nofollow\">ZhongAn Tech</a></li>\n    <li><a href=\"http://www.jchl.com/\" rel=\"nofollow\">JinCaiHuLian</a></li>\n    <li><a href=\"https://www.lianlianpay.com/\" rel=\"nofollow\">Lianlian Pay</a></li>\n    <li><a href=\"http://www.yaolaivip.com/\" rel=\"nofollow\">SR online</a></li>\n    <li><a href=\"http://www.icinfo.cn/\" rel=\"nofollow\">IcInfo</a></li>\n    <li><a href=\"https://www.laocaibao.com/\" rel=\"nofollow\">LaoCaiBao</a></li>\n    <li><a href=\"https://www.kaniu.com/\" rel=\"nofollow\">NiuCard</a></li>\n    <li><a href=\"http://www.jiedaibao.com/\" rel=\"nofollow\">JieDaiBao</a></li>\n    <li><a href=\"https://www.jinhui365.com/\" rel=\"nofollow\">JinHui365</a></li>\n    <li><a href=\"http://www.91techgroup.com/\" rel=\"nofollow\">91 Tech Group</a></li>\n</ul>\n\n### Digitalization and Cloud Services\n<ul>\n    <li><a href=\"http://www.yunjiacloud.com/\" rel=\"nofollow\">YunJia cloud</a></li>\n    <li><a href=\"https://www.joyowo.com/\" rel=\"nofollow\">Joyowo</a></li>\n    <li><a href=\"https://www.treebear.cn/\" rel=\"nofollow\">Tree Bear</a></li>\n    <li><a href=\"https://www.szdgri.com/\" rel=\"nofollow\">南方电网深圳数研院</a></li>\n</ul>\n\n### Transportation\n<ul>\n    <li><a href=\"http://www.juneyaoair.com/\" rel=\"nofollow\">JUNEYAO AIR</a></li>\n    <li><a href=\"https://www.caocaokeji.cn/\" rel=\"nofollow\">CaoCao</a></li>\n    <li><a href=\"https://www.tuhu.cn/\" rel=\"nofollow\">Tuhu</a></li>\n    <li><a href=\"https://www.01zhuanche.com/\" rel=\"nofollow\">ShouQi</a></li>\n    <li><a href=\"https://www.itrip.com/\" rel=\"nofollow\">iTrip</a></li>\n    <li><a href=\"https://www.maihaoche.com/\" rel=\"nofollow\">MaiHaoche</a></li>\n    <li><a href=\"https://www.ttpai.cn/\" rel=\"nofollow\">TTPai</a></li>\n    <li><a href=\"https://www.didiglobal.com/\" rel=\"nofollow\">DiDi</a></li>\n</ul>\n\n### Logistics\n<ul>\n    <li><a href=\"http://www.yto.net.cn/\" rel=\"nofollow\">YR Express</a></li>\n    <li><a href=\"http://www.haoyunhu56.com/\" rel=\"nofollow\">HaoYunHu</a></li>\n    <li><a href=\"http://www.dekuncn.com/\" rel=\"nofollow\">DeKun</a></li>\n</ul>\n\n### Real Estate\n<ul>\n    <li><a href=\"http://www.ziroom.com/\" rel=\"nofollow\">ZIroom</a></li>\n    <li><a href=\"https://www.ucommune.com/\" rel=\"nofollow\">UCommune</a></li>\n    <li><a href=\"https://www.lianjia.com/\" rel=\"nofollow\">LianJia</a></li>\n</ul>\n\n### E-education\n<ul>\n    <li><a href=\"https://www.ibeiliao.com/\" rel=\"nofollow\">IBeiLiao</a></li>\n    <li><a href=\"http://www.iqihang.com/\" rel=\"nofollow\">IQiHang</a></li>\n    <li><a href=\"https://willclass.com/\" rel=\"nofollow\">Will Class</a></li>\n    <li><a href=\"http://www.thinktown.com/\" rel=\"nofollow\">Think Town</a></li>\n    <li><a href=\"https://www.genshuixue.com/\" rel=\"nofollow\">GSX</a></li>\n    <li><a href=\"https://www.qidianla.com/\" rel=\"nofollow\">Qidian</a></li>\n</ul>\n\n### E-entertainment\n<ul>\n    <li><a href=\"https://g.10086.cn/\" rel=\"nofollow\">MiguFun</a></li>\n    <li><a href=\"https://www.motie.com/\" rel=\"nofollow\">motie</a></li>\n    <li><a href=\"http://changemax.cn/\" rel=\"nofollow\">squirrel</a></li>\n</ul>\n\n### News\n<ul>\n    <li><a href=\"http://bj.fangjia.com/\" rel=\"nofollow\">FangJia</a></li>\n    <li><a href=\"https://auto.ifeng.com/\" rel=\"nofollow\">IFeng</a></li>\n    <li><a href=\"https://www.taoguba.com.cn/\" rel=\"nofollow\">Taoguba</a></li>\n    <li><a href=\"https://www.fanhaoyue.com/\" rel=\"nofollow\">FanHaoYue</a></li>\n    <li><a href=\"https://www.sohu.com/\" rel=\"nofollow\">SOHU</a></li>\n</ul>\n\n### Communication\n<ul>\n    <li><a href=\"https://www.meizu.com/\" rel=\"nofollow\">MeiZu</a></li>\n    <li><a href=\"https://www.oneplus.com/cn\" rel=\"nofollow\">OnePlus</a></li>\n</ul>\n\n### Internet of Things\n<ul>\n    <li><a href=\"https://thinkiot.lenovo.com/\" rel=\"nofollow\">Lenovo</a></li>\n    <li><a href=\"http://www.neoway.com/\" rel=\"nofollow\">Neoway</a></li>\n    <li><a href=\"https://www.gizwits.com/\" rel=\"nofollow\">Gizwits</a></li>\n    <li><a href=\"http://www.gdyuanpeng.com/\" rel=\"nofollow\">YY Cloud</a></li>\n    <li><a href=\"https://www.g7.com.cn/\" rel=\"nofollow\">G7</a></li>\n    <li><a href=\"http://www.glsx.com.cn/\">ShenzhenGuangliansaixun Co.，LTD.</a></li>\n    <li><a href=\"https://sunwuu.com\">Guangzhou shang mai network technology co. LTD</a></li>\n</ul>\n\n### Software Development Services\n<ul>\n    <li><a href=\"https://www.ultrapower.com.cn/\" rel=\"nofollow\">ultrapower</a></li>\n    <li><a href=\"http://www.duiba.com.cn\" rel=\"nofollow\">DuiBa Group</a></li>\n    <li><a href=\"http://www.cig.com.cn/\" rel=\"nofollow\">Cig</a></li>\n    <li><a href=\"https://cn.yeahmobi.com/\" rel=\"nofollow\">Yeahmobi</a></li>\n    <li><a href=\"http://www.leimingtech.com/\" rel=\"nofollow\">LeiMing</a></li>\n    <li><a href=\"https://www.zyzc8.com/\" rel=\"nofollow\">ZhongChuang Technology</a></li>\n    <li><a href=\"http://www.deepdraw.cn/\" rel=\"nofollow\">DeepDraw</a></li>\n    <li><a href=\"https://www.go-future.cn/\" rel=\"nofollow\">WeiLaiXinFeng</a></li>\n    <li><a href=\"http://www.gzcss.net/\" rel=\"nofollow\">Guangzhou Zhongruan</a></li>\n    <li><a href=\"https://www.shb.ltd/\" rel=\"nofollow\">PubLink</a></li>\n</ul>\n\n### Health Care\n<ul>\n    <li><a href=\"https://www.hh.global/\" rel=\"nofollow\">H&H Global</a></li>\n    <li><a href=\"http://www.yunyichina.cn/\" rel=\"nofollow\">Glory</a></li>\n    <li><a href=\"https://www.120yibao.com/\" rel=\"nofollow\">YIBAO</a></li>\n    <li><a href=\"https://www.sytown.cn/\" rel=\"nofollow\">SYTown</a></li>\n</ul>\n\n### Retail\n<ul>\n    <li><a href=\"http://www.yonghui.com.cn/\" rel=\"nofollow\">YH</a></li>\n</ul>\n\n### AI\n<ul>\n    <li><a href=\"https://www.deepblueai.com/\" rel=\"nofollow\">DeepBlue</a></li>\n</ul>\n\n<img src=\"https://shardingsphere.apache.org/community/image/powered-by.png\" width = \"30%\" height = \"30%\" align=\"right\" alt=\"Powered By ShardingSphere\" />\n"
  },
  {
    "path": "docs/content/quick-start/_index.cn.md",
    "content": "+++\npre = \"<b>2. </b>\"\ntitle = \"快速入门\"\nweight = 2\nchapter = true\n+++\n\n## 引入 Maven 依赖\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-bootstrap</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\n## 作业开发\n\n```java\npublic class MyJob implements SimpleJob {\n    \n    @Override\n    public void execute(ShardingContext context) {\n        switch (context.getShardingItem()) {\n            case 0: \n                // do something by sharding item 0\n                break;\n            case 1: \n                // do something by sharding item 1\n                break;\n            case 2: \n                // do something by sharding item 2\n                break;\n            // case n: ...\n        }\n    }\n}\n```\n\n## 作业配置\n\n```java\n    JobConfiguration jobConfig = JobConfiguration.newBuilder(\"MyJob\", 3).cron(\"0/5 * * * * ?\").build();\n```\n\n## 作业调度\n\n```java\npublic class MyJobDemo {\n    \n    public static void main(String[] args) {\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createJobConfiguration()).schedule();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"zk_host:2181\", \"my-job\"));\n        regCenter.init();\n        return regCenter;\n    }\n    \n    private static JobConfiguration createJobConfiguration() {\n        // 创建作业配置\n        // ...\n    }\n}\n```\n"
  },
  {
    "path": "docs/content/quick-start/_index.en.md",
    "content": "+++\npre = \"<b>2. </b>\"\ntitle = \"Quick Start\"\nweight = 2\nchapter = true\n+++\n\n## Import Maven Dependency\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-bootstrap</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\n## Develop Job\n\n```java\npublic class MyJob implements SimpleJob {\n    \n    @Override\n    public void execute(ShardingContext context) {\n        switch (context.getShardingItem()) {\n            case 0: \n                // do something by sharding item 0\n                break;\n            case 1: \n                // do something by sharding item 1\n                break;\n            case 2: \n                // do something by sharding item 2\n                break;\n            // case n: ...\n        }\n    }\n}\n```\n\n## Configure Job\n\n```java\n    JobConfiguration jobConfig = JobConfiguration.newBuilder(\"MyJob\", 3).cron(\"0/5 * * * * ?\").build();\n```\n\n## Schedule Job\n\n```java\npublic class MyJobDemo {\n    \n    public static void main(String[] args) {\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createJobConfiguration()).schedule();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"zk_host:2181\", \"my-job\"));\n        regCenter.init();\n        return regCenter;\n    }\n    \n    private static JobConfiguration createJobConfiguration() {\n        // create job configuration\n        // ...\n    }\n}\n```\n\n"
  },
  {
    "path": "docs/content/user-manual/_index.cn.md",
    "content": "+++\npre = \"<b>4. </b>\"\ntitle = \"用户手册\"\nweight = 4\nchapter = true\n+++\n\nElasticJob 定位为轻量级无中心化解决方案，使用 jar 的形式提供分布式任务的协调服务。\n\n![ElasticJob Architecture](https://shardingsphere.apache.org/elasticjob/current/img/architecture/elasticjob_lite.png)\n\n他的优势在于无中心化设计且外部依赖少，适用于资源分配稳定的业务系统。\n"
  },
  {
    "path": "docs/content/user-manual/_index.en.md",
    "content": "+++\npre = \"<b>4. </b>\"\ntitle = \"User Manual\"\nweight = 4\nchapter = true\n+++\n\nElasticJob is a lightweight, decentralized solution that provides distributed task sharding services.\n\n![ElasticJob Architecture](https://shardingsphere.apache.org/elasticjob/current/img/architecture/elasticjob_lite.png)\n\nThe advantages of ElasticJob are no centralized design and less external dependence,\nwhich is suitable for business application with stable resource allocation. \n"
  },
  {
    "path": "docs/content/user-manual/configuration/_index.cn.md",
    "content": "+++\npre = \"<b>4.1.2 </b>\"\ntitle = \"配置手册\"\nweight = 2\nchapter = true\n+++\n\n通过配置可以快速清晰的理解 ElasticJob 所提供的功能。\n\n本章节是 ElasticJob 的配置参考手册，需要时可当做字典查阅。\n\nElasticJob 提供了 3 种配置方式，用于不同的使用场景。\n\n## 注册中心配置项\n\n### 可配置属性\n\n| 属性名                           | 类型     | 缺省值   | 描述                  |\n|-------------------------------|:-------|:------|:--------------------|\n| serverLists                   | String |       | 连接 ZooKeeper 服务器的列表 |\n| namespace                     | String |       | ZooKeeper 的命名空间     |\n| baseSleepTimeMilliseconds     | int    | 1000  | 等待重试的间隔时间的初始毫秒数     |\n| maxSleepTimeMilliseconds      | String | 3000  | 等待重试的间隔时间的最大毫秒数     |\n| maxRetries                    | String | 3     | 最大重试次数              |\n| sessionTimeoutMilliseconds    | int    | 60000 | 会话超时毫秒数             |\n| connectionTimeoutMilliseconds | int    | 15000 | 连接超时毫秒数             |\n| digest                        | String | 无需验证  | 连接 ZooKeeper 的权限令牌  |\n\n### 核心配置项说明\n\n**serverLists:**\n\n包括 IP 地址和端口号，多个地址用逗号分隔，如: host1:2181,host2:2181\n\n\n## 作业配置项\n\n### 可配置属性\n\n| 属性名                               | 类型         | 缺省值            | 描述                   |\n|-----------------------------------|:-----------|:---------------|:---------------------|\n| jobName                           | String     |                | 作业名称                 |\n| shardingTotalCount                | int        |                | 作业分片总数               |\n| cron                              | String     |                | CRON 表达式，用于控制作业触发时间  |\n| timeZone                          | String     |                | CRON 的时区设置           |\n| shardingItemParameters            | String     |                | 个性化分片参数              |\n| jobParameter                      | String     |                | 作业自定义参数              |\n| monitorExecution                  | boolean    | true           | 监控作业运行时状态            |\n| failover                          | boolean    | false          | 是否开启任务执行失效转移         |\n| misfire                           | boolean    | true           | 是否开启错过任务重新执行         |\n| maxTimeDiffSeconds                | int        | -1（不检查）        | 最大允许的本机与注册中心的时间误差秒数  |\n| reconcileIntervalMinutes          | int        | 10             | 修复作业服务器不一致状态服务调度间隔分钟 |\n| jobShardingStrategyType           | String     | AVG_ALLOCATION | 作业分片策略类型             |\n| jobExecutorThreadPoolSizeProvider | String     | CPU            | 作业线程池处理策略            |\n| jobErrorHandlerType               | String     |                | 作业错误处理策略             |\n| description                       | String     |                | 作业描述信息               |\n| props                             | Properties |                | 作业属性配置信息             |\n| disabled                          | boolean    | false          | 作业是否禁止启动             |\n| overwrite                         | boolean    | false          | 本地配置是否可覆盖注册中心配置      |\n\n### 核心配置项说明\n\n**shardingItemParameters:**\n\n分片序列号和参数用等号分隔，多个键值对用逗号分隔。\n分片序列号从0开始，不可大于或等于作业分片总数。\n如：0=a,1=b,2=c\n\n**jobParameter:**\n\n可通过传递该参数为作业调度的业务方法传参，用于实现带参数的作业\n例：每次获取的数据量、作业实例从数据库读取的主键等。\n\n**monitorExecution:**\n\n每次作业执行时间和间隔时间均非常短的情况，建议不监控作业运行时状态以提升效率。\n因为是瞬时状态，所以无必要监控。请用户自行增加数据堆积监控。并且不能保证数据重复选取，应在作业中实现幂等性。\n每次作业执行时间和间隔时间均较长的情况，建议监控作业运行时状态，可保证数据不会重复选取。\n\n**maxTimeDiffSeconds:**\n\n如果时间误差超过配置秒数则作业启动时将抛异常。\n\n**reconcileIntervalMinutes:**\n\n在分布式的场景下由于网络、时钟等原因，可能导致 ZooKeeper 的数据与真实运行的作业产生不一致，这种不一致通过正向的校验无法完全避免。\n需要另外启动一个线程定时校验注册中心数据与真实作业状态的一致性，即维持 ElasticJob 的最终一致性。\n\n配置为小于 1 的任意值表示不执行修复。\n\n**jobShardingStrategyType:**\n\n详情请参见[内置分片策略列表](/cn/user-manual/elasticjob/configuration/built-in-strategy/sharding)。\n\n**jobExecutorThreadPoolSizeProviderType:**\n\n详情请参见[内置线程池策略列表](/cn/user-manual/elasticjob/configuration/built-in-strategy/thread-pool)。\n\n**jobErrorHandlerType:**\n\n详情请参见[内置错误处理策略列表](/cn/user-manual/elasticjob/configuration/built-in-strategy/error-handler)。\n\n**props:**\n\n详情请参见[作业属性配置列表](/cn/user-manual/elasticjob/configuration/props)。\n\n**disabled:**\n\n可用于部署作业时，先禁止启动，部署结束后统一启动。\n\n**overwrite:**\n\n如果可覆盖，每次启动作业都以本地配置为准。\n\n## 作业监听器配置项\n\n### 常规监听器配置项\n\n可配置属性：无\n\n### 分布式监听器配置项\n\n可配置属性\n\n| 属性名                          | 类型    | 缺省值          | 描述                               |\n| ------------------------------ |:------- |:-------------- |:---------------------------------- |\n| started-timeout-milliseconds   | long   | Long.MAX_VALUE | 最后一个作业执行前的执行方法的超时毫秒数 |\n| completed-timeout-milliseconds | long   | Long.MAX_VALUE | 最后一个作业执行后的执行方法的超时毫秒数 |\n\n## 事件追踪配置项\n\n### 可配置属性\n\n| 属性名   | 类型    | 缺省值 | 描述                 |\n| ------- |:------- |:----- |:------------------- |\n| type    | String  |       | 事件追踪存储适配器类型 |\n| storage | 泛型    |        | 事件追踪存储适配器对象 |\n"
  },
  {
    "path": "docs/content/user-manual/configuration/_index.en.md",
    "content": "+++\npre = \"<b>4.1.2 </b>\"\ntitle = \"Configuration\"\nweight = 2\nchapter = true\n+++\n\nThrough which developers can quickly and clearly understand the functions provided by ElasticJob.\n\nThis chapter is a configuration manual for ElasticJob, which can also be referred to as a dictionary if necessary.\n\nElasticJob has provided 3 kinds of configuration methods for different situations.\n\n## Registry Center Configuration\n\n### Configuration\n\n| Name                          | Data Type | Default Value | Description                                              |\n|-------------------------------|:----------|:--------------|:---------------------------------------------------------|\n| serverLists                   | String    |               | ZooKeeper server IP list                                 |\n| namespace                     | String    |               | ZooKeeper namespace                                      |\n| baseSleepTimeMilliseconds     | int       | 1000          | The initial value of milliseconds for the retry interval |\n| maxSleepTimeMilliseconds      | String    | 3000          | The maximum value of milliseconds for the retry interval |\n| maxRetries                    | String    | 3             | Maximum number of retries                                |\n| sessionTimeoutMilliseconds    | int       | 60000         | Session timeout in milliseconds                          |\n| connectionTimeoutMilliseconds | int       | 15000         | Connection timeout in milliseconds                       |\n| digest                        | String    | no need       | Permission token to connect to ZooKeeper                 |\n\n### Core Configuration Description\n\n**serverLists:**\n\nInclude IP and port, multiple addresses are separated by commas, such as: `host1:2181,host2:2181`\n\n## Job Configuration\n\n### Configuration\n\n| Name                              | Data Type  | Default Value  | Description                                                                         |\n|-----------------------------------|:-----------|:---------------|:------------------------------------------------------------------------------------|\n| jobName                           | String     |                | Job name                                                                            |\n| shardingTotalCount                | int        |                | Sharding total count                                                                |\n| cron                              | String     |                | CRON expression, control the job trigger time                                       |\n| timeZone                          | String     |                | time zone of CRON                                                                   |\n| shardingItemParameters            | String     |                | Sharding item parameters                                                            |\n| jobParameter                      | String     |                | Job parameter                                                                       |\n| monitorExecution                  | boolean    | true           | Monitor job execution status                                                        |\n| failover                          | boolean    | false          | Enable or disable job failover                                                      |\n| misfire                           | boolean    | true           | Enable or disable the missed task to re-execute                                     |\n| maxTimeDiffSeconds                | int        | -1(no check)   | The maximum value for time difference between server and registry center in seconds |\n| reconcileIntervalMinutes          | int        | 10             | Service scheduling interval in minutes for repairing job server inconsistent state  |\n| jobShardingStrategyType           | String     | AVG_ALLOCATION | Job sharding strategy type                                                          |\n| jobExecutorThreadPoolSizeProvider | String     | CPU            | Job thread pool handler type                                                        |\n| jobErrorHandlerType               | String     |                | Job error handler type                                                              |\n| description                       | String     |                | Job description                                                                     |\n| props                             | Properties |                | Job properties                                                                      |\n| disabled                          | boolean    | false          | Enable or disable start the job                                                     |\n| overwrite                         | boolean    | false          | Enable or disable local configuration override registry center configuration        |\n\n### Core Configuration Description\n\n**shardingItemParameters:**\n\nThe sequence numbers and parameters of the Sharding items are separated by equal sign, and multiple key-value pairs are separated by commas.\nThe Sharding sequence number starts from `0` and can't be greater than or equal to the total number of job fragments.\nFor example: `0=a,1=b,2=c`\n\n**jobParameter:**\n\nWith this parameter, user can pass parameters for the business method of job scheduling, which is used to implement the job with parameters.\nFor example: `Amount of data acquired each time`, `Primary key of the job instance read from the database`, etc.\n\n**monitorExecution:**\n\nWhen the execution time and interval of each job are very short, it is recommended not to monitor the running status of the job to improve efficiency.\nThere is no need to monitor because it is a transient state. User can add data accumulation monitoring by self. And there is no guarantee that the data will be selected repeatedly, idempotency should be achieved in the job.\nIf the job execution time and interval time are longer, it is recommended to monitor the job status, and it can guarantee that the data will not be selected repeatedly.\n\n**maxTimeDiffSeconds:**\n\nIf the time error exceeds the configured seconds, an exception will be thrown when the job starts.\n\n**reconcileIntervalMinutes:**\n\nIn a distributed system, due to network, clock and other reasons, ZooKeeper may be inconsistent with the actual running job. This inconsistency cannot be completely avoided through positive verification.\nIt is necessary to start another thread to periodically calibrate the consistency between the registry center and the job status, that is, to maintain the final consistency of ElasticJob.\n\nLess than `1` means no repair is performed.\n\n**jobShardingStrategyType:**\n\nFor details, see[Job Sharding Strategy](/en/user-manual/elasticjob/configuration/built-in-strategy/sharding)。\n\n**jobExecutorThreadPoolSizeProviderType:**\n\nFor details, see[Thread Pool Strategy](/en/user-manual/elasticjob/configuration/built-in-strategy/thread-pool)。\n\n**jobErrorHandlerType:**\n\nFor details, see[Error Handler Strategy](/en/user-manual/elasticjob/configuration/built-in-strategy/error-handler)。\n\n**props:**\n\nFor details, see[Job Properties](/en/user-manual/elasticjob/configuration/props)。\n\n**disabled:**\n\nIt can be used for deployment, forbid jobs to start, and then start them uniformly after the deployment is completed.\n\n**overwrite:**\n\nIf the value is `true`, local configuration override registry center configuration every time the job is started.\n\n## Job Listener Configuration\n\n### Common Listener Configuration\n\nConfiguration: no\n\n### Distributed Listener Configuration\n\nConfiguration\n\n| Name                           | Data Type    | Default Value  | Description                                                 |\n| ------------------------------ |:------------ |:-------------- |:----------------------------------------------------------- |\n| started-timeout-milliseconds   | long         | Long.MAX_VALUE | The timeout in milliseconds before the last job is executed |\n| completed-timeout-milliseconds | long         | Long.MAX_VALUE | The timeout in milliseconds after the last job is executed  |\n\n## Event Tracing Configuration\n\n### Configuration\n\n| Name    | Data Type      | Default Value | Description                                 |\n| ------- |:-------------- |:------------- |:------------------------------------------- |\n| type    | String         |               | The type of event tracing storage adapter   |\n| storage | Generics Type  |               | The object of event tracing storage adapter |\n"
  },
  {
    "path": "docs/content/user-manual/configuration/built-in-strategy/_index.cn.md",
    "content": "+++\ntitle = \"内置策略\"\nweight = 4\nchapter = true\n+++\n\n## 简介\n\nElasticJob 通过 SPI 方式允许开发者扩展策略；\n与此同时，ElasticJob 也提供了大量的内置策略以便于开发者使用。\n\n## 使用方式\n\n内置策略通过 type 进行配置。\n本章节根据功能区分并罗列 ElasticJob 全部的内置算法，供开发者参考。\n"
  },
  {
    "path": "docs/content/user-manual/configuration/built-in-strategy/_index.en.md",
    "content": "+++\ntitle = \"Built-in Strategy\"\nweight = 4\nchapter = true\n+++\n\n## Introduction\n\nElasticJob allows developers to implement strategies via SPI;\nAt the same time, ElasticJob also provides a couple of built-in strategies for simplify developers.\n\n## Usage\n\nThe built-in strategies are configured by type. \nThis chapter distinguishes and lists all the built-in strategies of ElasticJob according to its functions for developers' reference.\n"
  },
  {
    "path": "docs/content/user-manual/configuration/built-in-strategy/error-handler.cn.md",
    "content": "+++\ntitle = \"错误处理策略\"\nweight = 3\n+++\n\n## 记录日志策略\n\n类型：LOG\n\n默认内置：是\n\n记录作业异常日志，但不中断作业执行。\n\n## 抛出异常策略\n\n类型：THROW\n\n默认内置：是\n\n抛出系统异常并中断作业执行。\n\n## 忽略异常策略\n\n类型：IGNORE\n\n默认内置：是\n\n忽略系统异常且不中断作业执行。\n\n## 邮件通知策略\n\n类型：EMAIL\n\n默认内置：否\n\n发送邮件消息通知，但不中断作业执行。\n\nMaven 坐标：\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-email</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\n可配置属性：\n\n| 属性名          | 说明                | 是否必填  | 默认值                    |\n| -------------- |:------------------- |:-------- |:------------------------ |\n| email.host     | 邮件服务器地址        | 是       | -                        |\n| email.port     | 邮件服务器端口        | 是       | -                        |\n| email.username | 邮件服务器用户名      | 是       | -                        |\n| email.password | 邮件服务器密码        | 是       | -                        |\n| email.useSsl   | 是否启用 SSL 加密传输 | 否       | true                     |\n| email.subject  | 邮件主题             | 否       | ElasticJob error message |\n| email.from     | 发送方邮箱地址        | 是       | -                        |\n| email.to       | 接收方邮箱地址        | 是       | -                        |\n| email.cc       | 抄送邮箱地址          | 否       | null                     |\n| email.bcc      | 密送邮箱地址          | 否       | null                     |\n| email.debug    | 是否开启调试模式      | 否       | false                    |\n\n## 企业微信通知策略\n\n类型：WECHAT\n\n默认内置：否\n\n发送企业微信消息通知，但不中断作业执行。\n\nMaven 坐标：\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-wechat</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\n可配置属性：\n\n| 属性名                             | 说明                                | 是否必填    | 默认值    |\n| --------------------------------- |:----------------------------------- |:--------- |:--------- |\n| wechat.webhook                    | 企业微信机器人的 webhook 地址         | 是         | -         |\n| wechat.connectTimeoutMilliseconds | 与企业微信服务器建立连接的超时时间      | 否         | 3000 毫秒 |\n| wechat.readTimeoutMilliseconds    | 从企业微信服务器读取到可用资源的超时时间 | 否         | 5000 毫秒 |\n\n## 钉钉通知策略\n\n类型：DINGTALK\n\n默认内置：否\n\n发送钉钉消息通知，但不中断作业执行。\n\nMaven 坐标：\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\n可配置属性：\n\n| 属性名                               | 说明                              | 是否必填 | 默认值    |\n| ----------------------------------- |:----------------------------------|:------- |:-------- |\n| dingtalk.webhook                    | 钉钉机器人的 webhook 地址           | 是       | -       |\n| dingtalk.keyword                    | 自定义关键词                       | 否       | null     |\n| dingtalk.secret                     | 签名的密钥                         | 否       | null     |\n| dingtalk.connectTimeoutMilliseconds | 与钉钉服务器建立连接的超时时间       | 否       | 3000 毫秒 |\n| dingtalk.readTimeoutMilliseconds    | 从钉钉服务器读取到可用资源的超时时间  | 否       | 5000 毫秒 |\n"
  },
  {
    "path": "docs/content/user-manual/configuration/built-in-strategy/error-handler.en.md",
    "content": "+++\ntitle = \"Error Handler Strategy\"\nweight = 3\n+++\n\n## Log Strategy\n\nType: LOG\n\nBuilt-in: Yes\n\nLog error and do not interrupt job.\n\n## Throw Strategy\n\nType: THROW\n\nBuilt-in: Yes\n\nThrow system exception and interrupt job.\n\n## Ignore Strategy\n\nType: IGNORE\n\nBuilt-in: Yes\n\nIgnore exception and do not interrupt job.\n\n## Email Notification Strategy\n\nType: EMAIL\n\nBuilt-in: No\n\nSend email message notification and do not interrupt job.\n\nMaven POM: \n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-email</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\nConfiguration: \n\n| Name           | Description                                  | Required | Default Value            |\n| -------------- |:-------------------------------------------- |:-------- |:------------------------ |\n| email.host     | Email server host address                    | Yes      | -                        |\n| email.port     | Email server port                            | Yes      | -                        |\n| email.username | Email server username                        | Yes      | -                        |\n| email.password | Email server password                        | Yes      | -                        |\n| email.useSsl   | Whether to enable SSL encrypted transmission | No       | true                     |\n| email.subject  | Email Subject                                | No       | ElasticJob error message |\n| email.from     | Sender email address                         | Yes      | -                        |\n| email.to       | Recipient's email address                    | Yes      | -                        |\n| email.cc       | Carbon copy email address                    | No       | null                     |\n| email.bcc      | Blind carbon copy email address              | No       | null                     |\n| email.debug    | Whether to enable debug mode                 | No       | false                    |\n\n## Wechat Enterprise Notification Strategy\n\nType: WECHAT\n\nBuilt-in: No\n\nSend wechat message notification and do not interrupt job\n\nMaven POM: \n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-wechat</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\nConfiguration: \n\n| Name                              | Description                                                               | Required | Default Value     |\n| --------------------------------- |:------------------------------------------------------------------------- |:-------- |:----------------- |\n| wechat.webhook                    | The webhook address of the wechat robot                                   | Yes      | -                 |\n| wechat.connectTimeoutMilliseconds | The timeout period for establishing a connection with the wechat server   | No       | 3000 milliseconds |\n| wechat.readTimeoutMilliseconds    | The timeout period for reading available resources from the wechat server | No       | 5000 milliseconds |\n\n## Dingtalk Notification Strategy\n\nType: DINGTALK\n\nBuilt-in: No\n\nSend dingtalk message notification and do not interrupt job\n\nMaven POM: \n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\nConfiguration: \n\n| Name                                | Description                                                                 | Required | Default Value     |\n| ----------------------------------- |:--------------------------------------------------------------------------- |:-------- |:----------------- |\n| dingtalk.webhook                    | The webhook address of the dingtalk robot                                   | Yes      | -                 |\n| dingtalk.keyword                    | Custom keywords                                                             | No       | null              |\n| dingtalk.secret                     | Secret for dingtalk robot                                                   | No       | null              |\n| dingtalk.connectTimeoutMilliseconds | The timeout period for establishing a connection with the dingtalk server   | No       | 3000 milliseconds |\n| dingtalk.readTimeoutMilliseconds    | The timeout period for reading available resources from the dingtalk server | No       | 5000 milliseconds |\n"
  },
  {
    "path": "docs/content/user-manual/configuration/built-in-strategy/sharding.cn.md",
    "content": "+++\ntitle = \"作业分片策略\"\nweight = 1\n+++\n\n## 平均分片策略\n\n类型：AVG_ALLOCATION\n\n根据分片项平均分片。\n\n如果作业服务器数量与分片总数无法整除，多余的分片将会顺序的分配至每一个作业服务器。\n \n举例说明：\n1. 如果 3 台作业服务器且分片总数为9，则分片结果为：1=[0,1,2], 2=[3,4,5], 3=[6,7,8]；\n2. 如果 3 台作业服务器且分片总数为8，则分片结果为：1=[0,1,6], 2=[2,3,7], 3=[4,5]；\n3. 如果 3 台作业服务器且分片总数为10，则分片结果为：1=[0,1,2,9], 2=[3,4,5], 3=[6,7,8]。\n\n## 奇偶分片策略\n\n类型：ODEVITY\n\n根据作业名称哈希值的奇偶数决定按照作业服务器 IP 升序或是降序的方式分片。\n\n如果作业名称哈希值是偶数，则按照 IP 地址进行升序分片；\n如果作业名称哈希值是奇数，则按照 IP 地址进行降序分片。\n可用于让服务器负载在多个作业共同运行时分配的更加均匀。\n \n举例说明：\n1. 如果 3 台作业服务器，分片总数为2且作业名称的哈希值为偶数，则分片结果为：1 = [0], 2 = [1], 3 = []；\n2. 如果 3 台作业服务器，分片总数为2且作业名称的哈希值为奇数，则分片结果为：3 = [0], 2 = [1], 1 = []。\n\n## 轮询分片策略\n\n类型：ROUND_ROBIN\n\n根据作业名称轮询分片。\n"
  },
  {
    "path": "docs/content/user-manual/configuration/built-in-strategy/sharding.en.md",
    "content": "+++\ntitle = \"Job Sharding Strategy\"\nweight = 1\n+++\n\n## Average Allocation Strategy\n\nType: AVG_ALLOCATION\n\nSharding or average by sharding item.\n\nIf the job server number and sharding count cannot be divided, \nthe redundant sharding item that cannot be divided will be added to the server with small sequence number in turn.\n \nFor example: \n1. If there are 3 job servers and the total sharding count is 9, each job server is divided into: 1=[0,1,2], 2=[3,4,5], 3=[6,7,8];\n2. If there are 3 job servers and the total sharding count is 8, each job server is divided into: 1=[0,1,6], 2=[2,3,7], 3=[4,5];\n3. If there are 3 job servers and the total sharding count is 10, each job server is divided into: 1=[0,1,2,9], 2=[3,4,5], 3=[6,7,8].\n\n## Odevity Strategy\n\nType: ODEVITY\n\nSharding for hash with job name to determine IP asc or desc.\n\nIP address asc if job name' hashcode is odd;\nIP address desc if job name' hashcode is even.\nUsed to average assign to job server.\n \nFor example: \n1. If there are 3 job servers with 2 sharding item, and the hash value of job name is odd, then each server is divided into: 1 = [0], 2 = [1], 3 = [];\n2. If there are 3 job servers with 2 sharding item, and the hash value of job name is even, then each server is divided into: 3 = [0], 2 = [1], 1 = [].\n\n## Round Robin Strategy\n\nType: ROUND_ROBIN\n\nSharding for round robin by name job.\n"
  },
  {
    "path": "docs/content/user-manual/configuration/built-in-strategy/thread-pool.cn.md",
    "content": "+++\ntitle = \"线程池策略\"\nweight = 2\n+++\n\n## CPU 资源策略\n\n类型：CPU\n\n根据 CPU 核数 * 2 创建作业处理线程池。\n\n## 单线程策略\n\n类型：SINGLE_THREAD\n\n使用单线程处理作业。\n"
  },
  {
    "path": "docs/content/user-manual/configuration/built-in-strategy/thread-pool.en.md",
    "content": "+++\ntitle = \"Thread Pool Strategy\"\nweight = 2\n+++\n\n## CPU Resource Strategy\n\nType: CPU\n\nUse CPU available processors * 2 to create thread pool.\n\n## Single Thread Strategy\n\nType: SINGLE_THREAD\n\nUse single thread to execute job.\n"
  },
  {
    "path": "docs/content/user-manual/configuration/external-integration/_index.cn.md",
    "content": "+++\ntitle = \"外部集成\"\nweight = 4\nchapter = true\n+++\n\n## 简介\n\nElasticJob 存在部分已知的外部集成，这些集成与 ElasticJob 的 API 基本无关。\n"
  },
  {
    "path": "docs/content/user-manual/configuration/external-integration/_index.en.md",
    "content": "+++\ntitle = \"External Integration\"\nweight = 4\nchapter = true\n+++\n\n## Introduction\n\nElasticJob has some known external integrations that are largely unrelated to ElasticJob's API.\n"
  },
  {
    "path": "docs/content/user-manual/configuration/external-integration/sasl.cn.md",
    "content": "+++\ntitle = \"连接至开启 SASL 鉴权的 Zookeeper Server\"\nweight = 2\n+++\n\n## 使用方式\n\nElasticJob 的 `org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter` 能正常连接至开启 SASL 鉴权的 Zookeeper Server。\nSASL 机制允许在客户端和服务器之间实现安全通信，而 ZooKeeper 支持 Kerberos 或 DIGEST-MD5 作为身份验证方案。\n下文讨论常见情景。\n\n### DIGEST-MD5\n\n假设通过 Docker Engine 部署单个 Zookeeper Server 实例，对应的 `docker-compose.yml` 内容如下，\n\n```yaml\nservices:\n  zookeeper-test:\n    image: zookeeper:3.9.2\n    volumes:\n      - ./jaas-server-test.conf:/jaas-test.conf\n    environment:\n      JVMFLAGS: \"-Djava.security.auth.login.config=/jaas-test.conf\"\n      ZOO_CFG_EXTRA: \"authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider sessionRequireClientSASLAuth=true\"\n    ports:\n      - \"2181:2181\"\n```\n\n假设存在文件为 `./jaas-server-test.conf`，内容如下，\n\n```\nServer {\n    org.apache.zookeeper.server.auth.DigestLoginModule required\n    user_bob=\"bobsecret\";\n};\n```\n\n假设存在独立的 Spring Boot 应用，只需要在 Spring Boot 的启动类配置 SASL 的鉴权信息。逻辑类似如下，\n\n```java\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.Configuration;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class ExampleUtils {\n    public void initSasl() {\n        Configuration configuration = new Configuration() {\n            @Override\n            public AppConfigurationEntry[] getAppConfigurationEntry(final String name) {\n                Map<String, String> conf = new HashMap<>();\n                conf.put(\"username\", \"bob\");\n                conf.put(\"password\", \"bobsecret\");\n                AppConfigurationEntry[] entries = new AppConfigurationEntry[1];\n                entries[0] = new AppConfigurationEntry(\n                        \"org.apache.zookeeper.server.auth.DigestLoginModule\",\n                        AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,\n                        conf);\n                return entries;\n            }\n        };\n        Configuration.setConfiguration(configuration);\n    }\n}\n```\n\n此时可正常初始化 ElasticJob 的 `org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter`。逻辑类似如下，\n\n```java\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\n\npublic class ExampleUtils {\n    public CoordinatorRegistryCenter initElasticJob() {\n        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(\"127.0.0.1:2181\", \"test-namespace\");\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        regCenter.init();\n        return regCenter;\n    }\n}\n```\n\n对于单个 JVM 进程，同一时间只能存在单个 SASL 鉴权信息，因为 Zookeeper Client 通过 JAAS 机制读取 SASL 鉴权信息。\n若当前 Spring Boot 应用需切换到使用不同 SASL 鉴权信息的 Zookeeper Server，则需要注销已有的 SASL 鉴权信息。逻辑类似如下，\n\n```java\nimport javax.security.auth.login.Configuration;\n\npublic class ExampleUtils {\n    public void exitSasl() {\n        Configuration.setConfiguration(null);\n    }\n}\n```\n\n### Kerberos\n\n要使 ElasticJob 的 `org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter` 连接至开启 Kerberos 鉴权的 Zookeeper Server，\n流程类似于 DIGEST-MD5。以 https://cwiki.apache.org/confluence/display/ZOOKEEPER/Client-Server+mutual+authentication 为准。\n\nKerberos KDC 不存在可用的 Docker Image，用户可能需要手动启动 Kerberos KDC。\n"
  },
  {
    "path": "docs/content/user-manual/configuration/external-integration/sasl.en.md",
    "content": "+++\ntitle = \"Connect to Zookeeper Server with SASL authentication enabled\"\nweight = 2\n+++\n\n## Usage\n\nElasticJob's `org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter` can connect to Zookeeper Server with SASL authentication enabled.\nThe SASL mechanism allows secure communication between the client and the server, \nand ZooKeeper supports Kerberos or DIGEST-MD5 as authentication schemes.\nCommon scenarios are discussed below.\n\n### DIGEST-MD5\n\nAssuming that a single Zookeeper Server instance is deployed through Docker Engine, \nthe corresponding `docker-compose.yml` content is as follows,\n\n```yaml\nservices:\n  zookeeper-test:\n    image: zookeeper:3.9.2\n    volumes:\n      - ./jaas-server-test.conf:/jaas-test.conf\n    environment:\n      JVMFLAGS: \"-Djava.security.auth.login.config=/jaas-test.conf\"\n      ZOO_CFG_EXTRA: \"authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider sessionRequireClientSASLAuth=true\"\n    ports:\n      - \"2181:2181\"\n```\n\nAssume that there is a file called `./jaas-server-test.conf` with the following content:\n\n```\nServer {\n    org.apache.zookeeper.server.auth.DigestLoginModule required\n    user_bob=\"bobsecret\";\n};\n```\n\nAssuming there is an independent Spring Boot application, \nusers only need to configure SASL authentication information in the Spring Boot startup class. \nThe logic is similar to the following:\n\n```java\nimport javax.security.auth.login.AppConfigurationEntry;\nimport javax.security.auth.login.Configuration;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class ExampleUtils {\n    public void initSasl() {\n        Configuration configuration = new Configuration() {\n            @Override\n            public AppConfigurationEntry[] getAppConfigurationEntry(final String name) {\n                Map<String, String> conf = new HashMap<>();\n                conf.put(\"username\", \"bob\");\n                conf.put(\"password\", \"bobsecret\");\n                AppConfigurationEntry[] entries = new AppConfigurationEntry[1];\n                entries[0] = new AppConfigurationEntry(\n                        \"org.apache.zookeeper.server.auth.DigestLoginModule\",\n                        AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,\n                        conf);\n                return entries;\n            }\n        };\n        Configuration.setConfiguration(configuration);\n    }\n}\n```\n\nAt this time, the `org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter` of ElasticJob can be initialized normally. \nThe logic is similar to the following:\n\n```java\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\n\npublic class ExampleUtils {\n    public CoordinatorRegistryCenter initElasticJob() {\n        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(\"127.0.0.1:2181\", \"test-namespace\");\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        regCenter.init();\n        return regCenter;\n    }\n}\n```\n\nFor a single JVM process, only one SASL authentication information can exist at the same time, \nbecause Zookeeper Client reads SASL authentication information through the JAAS mechanism.\nIf the current Spring Boot application needs to switch to a Zookeeper Server that uses different SASL authentication information, \nthe existing SASL authentication information needs to be deregistered. \nThe logic is similar to the following,\n\n```java\nimport javax.security.auth.login.Configuration;\n\npublic class ExampleUtils {\n    public void exitSasl() {\n        Configuration.setConfiguration(null);\n    }\n}\n```\n\n### Kerberos\n\nTo connect ElasticJob's `org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter` to Zookeeper Server with Kerberos authentication enabled,\nthe process is similar to DIGEST-MD5. \nRefer to https://cwiki.apache.org/confluence/display/ZOOKEEPER/Client-Server+mutual+authentication .\n\nThere is no available Docker Image for Kerberos KDC. Users may need to start Kerberos KDC manually.\n"
  },
  {
    "path": "docs/content/user-manual/configuration/graalvm-native-image.cn.md",
    "content": "+++\ntitle = \"GraalVM Native Image\"\nweight = 6\nchapter = true\n+++\n\n## 背景信息\n\nElasticJob 已在 GraalVM Native Image 下完成可用性验证。\n\n构建包含 `org.apache.shardingsphere.elasticjob:elasticjob-bootstrap:${elasticjob.version}` 的 Maven 依赖的 GraalVM Native Image，\n你需要借助于 GraalVM Native Build Tools。\nGraalVM Native Build Tools 提供了 Maven Plugin 和 Gradle Plugin 来简化 GraalVM CE 的 `native-image` 命令行工具的长篇大论的 shell 命令。\n\nElasticJob 要求在如下或更高版本的 `GraalVM CE` 完成构建 GraalVM Native Image。使用者可通过 `SDKMAN!` 快速切换 JDK。这同理\n适用于 https://sdkman.io/jdks#graal ， https://sdkman.io/jdks#nik 和 https://sdkman.io/jdks#mandrel 等 `GraalVM CE` 的下游发行版。\n\n- GraalVM CE For JDK 22.0.2，对应于 SDKMAN! 的 `22.0.2-graalce`\n\n用户依然可以使用 SDKMAN! 上的 `21.0.2-graalce` 等旧版本的 GraalVM CE 来构建 ElasticJob 的 GraalVM Native Image 产物。\nElasticJob 不为已停止维护的 GraalVM CE 版本设置 CI。\n\n## 使用 ElasticJob 的 Java API\n\n### Maven 生态\n\n使用者需要主动使用 GraalVM Reachability Metadata 中央仓库。\n如下配置可供参考，以配置项目额外的 Maven Profiles，以 GraalVM Native Build Tools 的文档为准。\n\n```xml\n<project>\n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-bootstrap</artifactId>\n            <version>${elasticjob.version}</version>\n        </dependency>\n    </dependencies>\n    \n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.graalvm.buildtools</groupId>\n                <artifactId>native-maven-plugin</artifactId>\n                <version>0.10.3</version>\n                <extensions>true</extensions>\n                <executions>\n                    <execution>\n                        <id>build-native</id>\n                        <goals>\n                            <goal>compile-no-fork</goal>\n                        </goals>\n                        <phase>package</phase>\n                    </execution>\n                    <execution>\n                        <id>test-native</id>\n                        <goals>\n                            <goal>test</goal>\n                        </goals>\n                        <phase>test</phase>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n```\n\n### Gradle 生态\n\n使用者需要主动使用 GraalVM Reachability Metadata 中央仓库。\n如下配置可供参考，以配置项目额外的 Gradle Tasks，以 GraalVM Native Build Tools 的文档为准。\n由于 https://github.com/gradle/gradle/issues/17559 的限制，用户需要通过 Maven 依赖的形式引入 Metadata Repository 的 JSON 文件。\n参考 https://github.com/graalvm/native-build-tools/issues/572 。\n\n```groovy\nplugins {\n   id 'org.graalvm.buildtools.native' version '0.10.3'\n}\n\ndependencies {\n   implementation 'org.apache.shardingsphere.elasticjob:elasticjob-bootstrap:${elasticjob.version}'\n   implementation(group: 'org.graalvm.buildtools', name: 'graalvm-reachability-metadata', version: '0.10.3', classifier: 'repository', ext: 'zip')\n}\n\ngraalvmNative {\n   metadataRepository {\n        enabled.set(false)\n   }\n}\n```\n\n## 使用 ElasticJob 的 Spring Boot Starter\n\n### Maven 生态\n\n使用者需要主动使用 GraalVM Reachability Metadata 中央仓库。\n如下配置可供参考，以配置项目额外的 Maven Profiles，以 GraalVM Native Build Tools 的文档为准。\n\n```xml\n<project>\n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-spring-boot-starter</artifactId>\n            <version>${elasticjob.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <version>3.3.4</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <version>3.3.4</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    \n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.graalvm.buildtools</groupId>\n                <artifactId>native-maven-plugin</artifactId>\n                <version>0.10.3</version>\n                <extensions>true</extensions>\n                <executions>\n                    <execution>\n                        <id>build-native</id>\n                        <goals>\n                            <goal>compile-no-fork</goal>\n                        </goals>\n                        <phase>package</phase>\n                    </execution>\n                    <execution>\n                        <id>test-native</id>\n                        <goals>\n                            <goal>test</goal>\n                        </goals>\n                        <phase>test</phase>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>3.3.4</version>\n                <executions>\n                    <execution>\n                        <id>process-test-aot</id>\n                        <goals>\n                            <goal>process-test-aot</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n```\n\n### Gradle 生态\n\n使用者需要主动使用 GraalVM Reachability Metadata 中央仓库。\n如下配置可供参考，以配置项目额外的 Gradle Tasks，以 GraalVM Native Build Tools 的文档为准。\n由于 https://github.com/gradle/gradle/issues/17559 的限制，用户需要通过 Maven 依赖的形式引入 Metadata Repository 的 JSON 文件。\n参考 https://github.com/graalvm/native-build-tools/issues/572 。\n\n```groovy\nplugins {\n    id 'org.springframework.boot' version '3.3.4'\n    id 'io.spring.dependency-management' version '1.1.6'\n    id 'org.graalvm.buildtools.native' version '0.10.3'\n}\n\ndependencies {\n    implementation 'org.springframework.boot:spring-boot-starter-web'\n    testImplementation 'org.springframework.boot:spring-boot-starter-test'\n    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'\n    implementation 'org.apache.shardingsphere.elasticjob:elasticjob-spring-boot-starter:${elasticjob.version}'\n    implementation(group: 'org.graalvm.buildtools', name: 'graalvm-reachability-metadata', version: '0.10.3', classifier: 'repository', ext: 'zip')\n}\n\ngraalvmNative {\n   metadataRepository {\n        enabled.set(false)\n   }\n}\n```\n\n## 对于 sbt 等不被 GraalVM Native Build Tools 支持的构建工具\n\n此类需求需要在 https://github.com/graalvm/native-build-tools 打开额外的 issue 并提供对应构建工具的 Plugin 实现。\n\n## 使用限制\n\n1. 使用者依然需要在 `src/main/resources/META-INF/native-image` 文件夹或 `src/test/resources/META-INF/native-image` 文件夹配置独立文件的 GraalVM Reachability Metadata。\n使用者可通过 GraalVM Native Build Tools 的 GraalVM Tracing Agent 来快速采集 GraalVM Reachability Metadata。\n\n2. 对于在 Linux 系统下执行 `elasticJobType` 为 `SCRIPT` 的 `org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap`，\n若 `script.command.line` 设置为构建 GraalVM Native Image 时， 私有项目的 classpath 下的某个 `.sh` 文件在 GraalVM Native Image 下的相对路径，\n则此 `.sh` 文件至少提前设置 `rwxr-xr-x` 的 POSIX 文件权限。\n因为 `com.oracle.svm.core.jdk.resources.NativeImageResourceFileSystem` 显然不支持 `java.nio.file.attribute.PosixFileAttributeView`。\n长话短说，用户应该避免在作业内包含类似如下的逻辑，\n\n```java\nimport java.io.IOException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.attribute.PosixFilePermissions;\n\npublic class ExampleUtils {\n    public void setPosixFilePermissions() throws IOException {\n        URL resource = ExampleUtils.class.getResource(\"/script/demo.sh\");\n        assert resource != null;\n        Path path = Paths.get(resource.getPath());\n        Files.setPosixFilePermissions(path, PosixFilePermissions.fromString(\"rwxr-xr-x\"));\n    }\n}\n```\n\n3. `企业微信通知策略`，`钉钉通知策略`，`邮件通知策略`尚未在 GraalVM Native Image 下可用。\n\n4. ElasticJob 的 Spring 命名空间集成模块 `org.apache.shardingsphere.elasticjob:elasticjob-spring-namespace` 尚未在 GraalVM Native Image 下可用。\n\n## 贡献 GraalVM Reachability Metadata\n\nElasticJob 对在 GraalVM Native Image 下的可用性的验证，是通过 GraalVM Native Build Tools 的 Maven Plugin 子项目来完成的。\n通过在 JVM 下运行单元测试，为单元测试打上 `junit-platform-unique-ids*` 标签，此后构建为 GraalVM Native Image 进行 nativeTest 来测试\n在 GraalVM Native Image 下的单元测试覆盖率。请贡献者不要使用 `io.kotest:kotest-runner-junit5-jvm:5.5.4` 等在 `test listener` mode 下\nfailed to discover tests 的测试库。\n\nElasticJob 定义了 `elasticjob-test-native` 的 Maven Module 用于为 native Test 提供小型的单元测试子集，\n此单元测试子集避免了使用 Mockito 等 native Test 下无法使用的第三方库。\n\nElasticJob 定义了 `nativeTestInElasticJob` 的 Maven Profile 用于为 `elasticjob-test-native` 模块执行 nativeTest 。\n\n假设贡献者处于新的 Ubuntu 22.04.4 LTS 实例下，其可通过如下 bash 命令通过 SDKMAN! 管理 JDK 和工具链，\n并为 `elasticjob-test-native` 子模块执行 nativeTest。\n\n贡献者必须安装 Docker Engine 以执行 `testcontainers-java` 相关的单元测试。\n\n```bash\nsudo apt install unzip zip curl sed -y\ncurl -s \"https://get.sdkman.io\" | bash\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk install java 22.0.2-graalce\nsdk use java 22.0.2-graalce\nsudo apt-get install build-essential zlib1g-dev -y\n\ngit clone git@github.com:apache/shardingsphere-elasticjob.git\ncd ./shardingsphere-elasticjob/\n./mvnw -PnativeTestInElasticJob -T1C -e clean test\n```\n\n当贡献者发现缺少与 ElasticJob 无关的第三方库的 GraalVM Reachability Metadata 时，应当在\nhttps://github.com/oracle/graalvm-reachability-metadata 打开新的 issue， 并提交包含依赖的第三方库缺失的 GraalVM Reachability\nMetadata 的 PR。ElasticJob 在 `elasticjob-reachability-metadata` 子模块主动托管了部分第三方库的 GraalVM Reachability Metadata。\n\n如果 nativeTest 执行失败， 应为单元测试生成初步的 GraalVM Reachability Metadata，\n并手动调整 `elasticjob-reachability-metadata` 子模块的 classpath 的 `META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-reachability-metadata/` 文件夹下的内容以修复 nativeTest。\n如有需要，请使用 `org.junit.jupiter.api.condition.DisabledInNativeImage` 注解或 `org.graalvm.nativeimage.imagecode` 的\nSystem Property 屏蔽部分单元测试在 GraalVM Native Image 下运行。\n\nElasticJob 定义了 `generateMetadata` 的 Maven Profile 用于在 GraalVM JIT Compiler 下携带 GraalVM Tracing Agent 执行单元测试，\n并在 `elasticjob-reachability-metadata` 子模块的 classpath 的 `META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/` 文件夹下，\n生成或覆盖已有的 GraalVM Reachability Metadata 文件。可通过如下 bash 命令简单处理此流程。\n贡献者仍可能需要手动调整具体的 JSON 条目，并适时调整 Maven Profile 和 GraalVM Tracing Agent 的 Filter 链。\n针对 `elasticjob-reachability-metadata` 子模块，\n手动增删改动的 JSON 条目应位于 `META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-reachability-metadata/` 文件夹下，\n而 `META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/` 中的条目仅应由 `generateMetadata` 的 Maven Profile 生成。\n\n以下命令仅为 `elasticjob-test-native` 生成 Conditional 形态的 GraalVM Reachability Metadata 的一个举例。\n生成的 GraalVM Reachability Metadata 位于 `elasticjob-reachability-metadata` 子模块下。\n\n对于测试类和测试文件独立使用的 GraalVM Reachability Metadata，贡献者应该放置到 `shardingsphere-test-native` 子模块的 classpath 的\n`META-INF/native-image/elasticjob-test-native-test-metadata/` 下。\n\n```bash\ngit clone git@github.com:apache/shardingsphere.git\ncd ./shardingsphere/\n./mvnw -PgenerateMetadata -DskipNativeTests -e -T1C clean test native:metadata-copy\n```\n"
  },
  {
    "path": "docs/content/user-manual/configuration/graalvm-native-image.en.md",
    "content": "+++\ntitle = \"GraalVM Native Image\"\nweight = 6\nchapter = true\n+++\n\n## Background information\n\nElasticJob has been verified for availability under GraalVM Native Image.\n\nTo build a GraalVM Native Image with the Maven dependency `org.apache.shardingsphere.elasticjob:elasticjob-bootstrap:${elasticjob.version}`,\nyou need to use GraalVM Native Build Tools.\n\nGraalVM Native Build Tools provides Maven Plugin and Gradle Plugin to simplify the long-winded shell commands of GraalVM CE's `native-image` command line tool.\n\nElasticJob requires the following or higher versions of `GraalVM CE` to build the GraalVM Native Image. Users can quickly switch JDKs through `SDKMAN!`. \nThis also applies to downstream distributions of `GraalVM CE` such as https://sdkman.io/jdks#graal, https://sdkman.io/jdks#nik and https://sdkman.io/jdks#mandrel.\n\n- GraalVM CE For JDK 22.0.2, corresponding to `22.0.2-graalce` of SDKMAN!\n\nUsers can still use old versions of GraalVM CE such as `21.0.2-graalce` on SDKMAN! to build ElasticJob's GraalVM Native Image product.\nElasticJob does not set CI for GraalVM CE versions that have stopped maintenance.\n\n## Using ElasticJob's Java API\n\n### Maven Ecosystem\n\nUsers need to actively use the GraalVM Reachability Metadata Central Repository.\nThe following configuration is for reference. To configure additional Maven Profiles for the project, \nrefer to the documentation of GraalVM Native Build Tools.\n\n```xml\n<project>\n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-bootstrap</artifactId>\n            <version>${elasticjob.version}</version>\n        </dependency>\n    </dependencies>\n    \n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.graalvm.buildtools</groupId>\n                <artifactId>native-maven-plugin</artifactId>\n                <version>0.10.3</version>\n                <extensions>true</extensions>\n                <executions>\n                    <execution>\n                        <id>build-native</id>\n                        <goals>\n                            <goal>compile-no-fork</goal>\n                        </goals>\n                        <phase>package</phase>\n                    </execution>\n                    <execution>\n                        <id>test-native</id>\n                        <goals>\n                            <goal>test</goal>\n                        </goals>\n                        <phase>test</phase>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n```\n\n### Gradle Ecosystem\n\nUsers need to actively use the GraalVM Reachability Metadata Central Repository.\nThe following configuration is for reference. To configure additional Gradle Tasks for the project, refer to the documentation of GraalVM Native Build Tools.\nDue to the limitations of https://github.com/gradle/gradle/issues/17559, users need to introduce the Metadata Repository JSON file in the form of Maven dependencies.\nRefer to https://github.com/graalvm/native-build-tools/issues/572.\n\n```groovy\nplugins {\n   id 'org.graalvm.buildtools.native' version '0.10.3'\n}\n\ndependencies {\n   implementation 'org.apache.shardingsphere.elasticjob:elasticjob-bootstrap:${elasticjob.version}'\n   implementation(group: 'org.graalvm.buildtools', name: 'graalvm-reachability-metadata', version: '0.10.3', classifier: 'repository', ext: 'zip')\n}\n\ngraalvmNative {\n   metadataRepository {\n        enabled.set(false)\n   }\n}\n```\n\n## Using ElasticJob's Spring Boot Starter\n\n### Maven Ecosystem\n\nUsers need to actively use the GraalVM Reachability Metadata Central Repository.\nThe following configuration is for reference. \nTo configure additional Maven Profiles for the project, refer to the documentation of GraalVM Native Build Tools.\n\n```xml\n<project>\n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-spring-boot-starter</artifactId>\n            <version>${elasticjob.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <version>3.3.4</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <version>3.3.4</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.graalvm.buildtools</groupId>\n                <artifactId>native-maven-plugin</artifactId>\n                <version>0.10.3</version>\n                <extensions>true</extensions>\n                <executions>\n                    <execution>\n                        <id>build-native</id>\n                        <goals>\n                            <goal>compile-no-fork</goal>\n                        </goals>\n                        <phase>package</phase>\n                    </execution>\n                    <execution>\n                        <id>test-native</id>\n                        <goals>\n                            <goal>test</goal>\n                        </goals>\n                        <phase>test</phase>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>3.3.4</version>\n                <executions>\n                    <execution>\n                        <id>process-test-aot</id>\n                        <goals>\n                            <goal>process-test-aot</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n```\n\n### Gradle Ecosystem\n\nUsers need to actively use the GraalVM Reachability Metadata Central Repository.\nThe following configuration is for reference. To configure additional Gradle Tasks for the project, refer to the documentation of GraalVM Native Build Tools.\nDue to the limitations of https://github.com/gradle/gradle/issues/17559, users need to introduce the Metadata Repository JSON file in the form of Maven dependencies.\nRefer to https://github.com/graalvm/native-build-tools/issues/572 .\n\n```groovy\nplugins {\n    id 'org.springframework.boot' version '3.3.4'\n    id 'io.spring.dependency-management' version '1.1.6'\n    id 'org.graalvm.buildtools.native' version '0.10.3'\n}\n\ndependencies {\n    implementation 'org.springframework.boot:spring-boot-starter-web'\n    testImplementation 'org.springframework.boot:spring-boot-starter-test'\n    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'\n    implementation 'org.apache.shardingsphere.elasticjob:elasticjob-spring-boot-starter:${elasticjob.version}'\n    implementation(group: 'org.graalvm.buildtools', name: 'graalvm-reachability-metadata', version: '0.10.3', classifier: 'repository', ext: 'zip')\n}\n\ngraalvmNative {\n    metadataRepository {\n        enabled.set(false)\n    }\n}\n```\n\n## For build tools such as sbt that are not supported by GraalVM Native Build Tools\n\nSuch requirements require opening additional issues at https://github.com/graalvm/native-build-tools and providing plugin implementations for the corresponding build tools.\n\n## Usage restrictions\n\n1. Users still need to configure GraalVM Reachability Metadata in separate files in the `src/main/resources/META-INF/native-image` folder or the `src/test/resources/META-INF/native-image` folder.\nUsers can quickly collect GraalVM Reachability Metadata through the GraalVM Tracing Agent of GraalVM Native Build Tools.\n\n2. For `org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap` with `elasticJobType` as `SCRIPT` under Linux, \nif `script.command.line` is set to the relative path of a `.sh` file in the private project's classpath under the GraalVM Native Image when building the GraalVM Native Image, \nthen the `.sh` file must at least have the POSIX file permission of `rwxr-xr-x` set in advance. \nThis is because `com.oracle.svm.core.jdk.resources.NativeImageResourceFileSystem` obviously does not support `java.nio.file.attribute.PosixFileAttributeView`.\nLong story short, users should avoid including logic like the following in their jobs,\n\n```java\nimport java.io.IOException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.attribute.PosixFilePermissions;\n\npublic class ExampleUtils {\n    public void setPosixFilePermissions() throws IOException {\n        URL resource = ExampleUtils.class.getResource(\"/script/demo.sh\");\n        assert resource != null;\n        Path path = Paths.get(resource.getPath());\n        Files.setPosixFilePermissions(path, PosixFilePermissions.fromString(\"rwxr-xr-x\"));\n    }\n}\n```\n\n3. `WeCom Notification Policy`, `DingTalk Notification Policy`, and `Email Notification Policy` are not yet available under GraalVM Native Image.\n\n4. The Spring namespace integration module `org.apache.shardingsphere.elasticjob:elasticjob-spring-namespace` of ElasticJob is not yet available under GraalVM Native Image.\n\n## Contribute GraalVM Reachability Metadata\n\nElasticJob's usability verification under GraalVM Native Image is done by the Maven Plugin subproject of GraalVM Native Build Tools.\n\nUnit test coverage under GraalVM Native Image is tested by running unit tests under JVM, \ntagging unit tests with `junit-platform-unique-ids*`, and then building GraalVM Native Image for nativeTest. \nContributors are requested not to use test libraries such as `io.kotest:kotest-runner-junit5-jvm:5.5.4` that failed to discover tests in `test listener` mode.\n\nElasticJob defines the `elasticjob-test-native` Maven Module to provide a small subset of unit tests for native Test,\nwhich avoids the use of third-party libraries such as Mockito that cannot be used under native Test.\n\nElasticJob defines the `nativeTestInElasticJob` Maven profile to execute nativeTest for the `elasticjob-test-native` module.\n\nAssuming the contributor is on a fresh Ubuntu 22.04.4 LTS instance, he can use SDKMAN! to manage JDK and toolchains with the following bash command,\nand execute nativeTest for the `elasticjob-test-native` submodule.\n\nContributors must install Docker Engine to execute the `testcontainers-java` related unit tests.\n\n```bash\nsudo apt install unzip zip curl sed -y\ncurl -s \"https://get.sdkman.io\" | bash\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk install java 22.0.2-graalce\nsdk use java 22.0.2-graalce\nsudo apt-get install build-essential zlib1g-dev -y\n\ngit clone git@github.com:apache/shardingsphere-elasticjob.git\ncd ./shardingsphere-elasticjob/\n./mvnw -PnativeTestInElasticJob -T1C -e clean test\n```\n\nWhen contributors find that GraalVM Reachability Metadata for third-party libraries not related to ElasticJob is missing, \nthey should open a new issue at https://github.com/oracle/graalvm-reachability-metadata, \nand submit a PR with missing GraalVM Reachability Metadata for dependent third-party libraries. \nElasticJob proactively hosts GraalVM Reachability Metadata for some third-party libraries in the `elasticjob-reachability-metadata` submodule.\n\nIf nativeTest fails, generate preliminary GraalVM Reachability Metadata for unit tests, \nand manually adjust the contents of the `META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-reachability-metadata/` folder in the classpath of the `elasticjob-reachability-metadata` submodule to fix nativeTest.\nIf necessary, \nuse the `org.junit.jupiter.api.condition.DisabledInNativeImage` annotation or the `org.graalvm.nativeimage.imagecode` System Property to shield some unit tests from running under the GraalVM Native Image.\n\nElasticJob defines the `generateMetadata` Maven Profile to execute unit tests with the GraalVM Tracing Agent under the GraalVM JIT Compiler,\nand generates or overwrites the existing GraalVM Reachability Metadata file in the `META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/` folder in the classpath of the `elasticjob-reachability-metadata` submodule. \nThis process can be easily handled by the following bash command. \nContributors may still need to manually adjust specific JSON entries and adjust the filter chain of the Maven Profile and GraalVM Tracing Agent as appropriate. \nFor the `elasticjob-reachability-metadata` submodule,\nmanually added, deleted, and modified JSON entries should be located in the `META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-reachability-metadata/` folder,\nwhile the entries in `META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/` should only be generated by the `generateMetadata` Maven Profile.\n\nThe following command is just an example of generating Conditional GraalVM Reachability Metadata for `elasticjob-test-native`.\nThe generated GraalVM Reachability Metadata is located in the `elasticjob-reachability-metadata` submodule.\n\nFor GraalVM Reachability Metadata used independently by test classes and test files, \ncontributors should place it in the classpath of the shardingsphere-test-native submodule under `META-INF/native-image/elasticjob-test-native-test-metadata/`.\n\n```bash\ngit clone git@github.com:apache/shardingsphere.git\ncd ./shardingsphere/\n./mvnw -PgenerateMetadata -DskipNativeTests -e -T1C clean test native:metadata-copy\n```\n"
  },
  {
    "path": "docs/content/user-manual/configuration/java-api.cn.md",
    "content": "+++\ntitle = \"Java API\"\nweight = 1\nchapter = true\n+++\n\n## 注册中心配置\n\n用于注册和协调作业分布式行为的组件，目前仅支持 ZooKeeper。\n\n类名称：org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration\n\n可配置属性：\n\n| 属性名                           | 构造器注入 |\n|-------------------------------|:------|\n| serverLists                   | 是     |\n| namespace                     | 是     |\n| baseSleepTimeMilliseconds     | 否     |\n| maxSleepTimeMilliseconds      | 否     |\n| maxRetries                    | 否     |\n| sessionTimeoutMilliseconds    | 否     |\n| connectionTimeoutMilliseconds | 否     |\n| digest                        | 否     |\n\n## 作业配置\n\n类名称：org.apache.shardingsphere.elasticjob.api.JobConfiguration\n\n可配置属性：\n\n| 属性名                               | 构造器注入 |\n|-----------------------------------|:------|\n| jobName                           | 是     |\n| shardingTotalCount                | 是     |\n| cron                              | 否     |\n| timeZone                          | 否     |\n| shardingItemParameters            | 否     |\n| jobParameter                      | 否     |\n| monitorExecution                  | 否     |\n| failover                          | 否     |\n| misfire                           | 否     |\n| maxTimeDiffSeconds                | 否     |\n| reconcileIntervalMinutes          | 否     |\n| jobShardingStrategyType           | 否     |\n| jobExecutorThreadPoolSizeProvider | 否     |\n| jobErrorHandlerType               | 否     |\n| jobListenerTypes                  | 否     |\n| description                       | 否     |\n| props                             | 否     |\n| disabled                          | 否     |\n| overwrite                         | 否     |\n"
  },
  {
    "path": "docs/content/user-manual/configuration/java-api.en.md",
    "content": "+++\ntitle = \"Java API\"\nweight = 1\nchapter = true\n+++\n\n## Registry Center Configuration\n\nThe component which is used to register and coordinate the distributed behavior of jobs, currently only supports `ZooKeeper`.\n\nClass name: `org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration`\n\nConfiguration: \n\n| Name                          | Constructor injection |\n|-------------------------------|:----------------------|\n| serverLists                   | Yes                   |\n| namespace                     | Yes                   |\n| baseSleepTimeMilliseconds     | No                    |\n| maxSleepTimeMilliseconds      | No                    |\n| maxRetries                    | No                    |\n| sessionTimeoutMilliseconds    | No                    |\n| connectionTimeoutMilliseconds | No                    |\n| digest                        | No                    |\n\n## Job Configuration\n\nClass name: `org.apache.shardingsphere.elasticjob.api.JobConfiguration`\n\nConfiguration: \n\n| Name                              | Constructor injection |\n|-----------------------------------|:----------------------|\n| jobName                           | Yes                   |\n| shardingTotalCount                | Yes                   |\n| cron                              | No                    |\n| timeZone                          | No                    |\n| shardingItemParameters            | No                    |\n| jobParameter                      | No                    |\n| monitorExecution                  | No                    |\n| failover                          | No                    |\n| misfire                           | No                    |\n| maxTimeDiffSeconds                | No                    |\n| reconcileIntervalMinutes          | No                    |\n| jobShardingStrategyType           | No                    |\n| jobExecutorThreadPoolSizeProvider | No                    |\n| jobErrorHandlerType               | No                    |\n| jobListenerTypes                  | No                    |\n| description                       | No                    |\n| props                             | No                    |\n| disabled                          | No                    |\n| overwrite                         | No                    |\n"
  },
  {
    "path": "docs/content/user-manual/configuration/props.cn.md",
    "content": "+++\ntitle = \"作业属性配置\"\nweight = 5\nchapter = true\n+++\n\n## 简介\n\nElasticJob 提供属性配置的方式为不同类型的作业提供定制化配置。\n\n## 作业类型\n\n### 简单作业\n\n接口名称：org.apache.shardingsphere.elasticjob.simple.job.SimpleJob\n\n可配置属性：无\n\n### 数据流作业\n\n接口名称：org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob\n\n可配置属性：\n\n| *名称*             | *数据类型*   | *说明*         | *默认值*  |\n| ----------------- | ----------- | -------------- | -------- |\n| streaming.process | boolean     | 是否开启流式处理 | false    |\n\n### 脚本作业\n\n类型：SCRIPT\n\n可配置属性：\n\n| *名称*               | *数据类型*   | *说明*           | *默认值*  |\n| ------------------- | ----------- | ---------------- | -------- |\n| script.command.line | String      | 脚本内容或运行路径 | -        |\n\n### HTTP作业\n\n类型：HTTP\n\n可配置属性：\n\n| *名称*                               | *数据类型*   | *说明*              |  *默认值*  |\n| ----------------------------------- | ----------- | ------------------ | --------  |\n| http.uri                            | String      | http请求uri         | -         |\n| http.method                         | String      | http请求方法         | -         |\n| http.data                           | String      | http请求数据         | -         |\n| http.connect.timeout.milliseconds   | String      | http连接超时         | 3000      |\n| http.read.timeout.milliseconds      | String      | http读超时           | 5000      |\n| http.content.type                   | String      | http请求ContentType  | -         |\n\n"
  },
  {
    "path": "docs/content/user-manual/configuration/props.en.md",
    "content": "+++\ntitle = \"Job Properties\"\nweight = 5\nchapter = true\n+++\n\n## Introduction\n\n`ElasticJob` provide customized configurations for different types of jobs through the way of attribute configuration.\n\n## Job Type\n\n### Simple Job\n\nInterface name: `org.apache.shardingsphere.elasticjob.simple.job.SimpleJob`\n\nConfiguration: no\n\n### Dataflow Job\n\nInterface name: `org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob`\n\nConfiguration: \n\n| *Name*             | *Data Type*   | *Description*               | *Default Value*  |\n| -----------------  | -----------   | --------------------------- | ---------------- |\n| streaming.process  | boolean       | Enable or disable Streaming | false            |\n\n### Script Job\n\nType: `SCRIPT`\n\nConfiguration: \n\n| *Name*               | *Data Type*   | *Description*           | *Default Value*  |\n| -------------------- | ------------- | ----------------------- | ---------------- |\n| script.command.line  | String        | Script content or path  | -                |\n\n### HTTP Job\n\nType：`HTTP`\n\nConfiguration: \n\n| *Name*                             | *Data Type*    | *Description*          |  *Default Value*  |\n| ---------------------------------- | -----------    | ----------------       | --------          |\n| http.uri                           | String         | http request uri       | -                 |\n| http.method                        | String         | http request method    | -                 |\n| http.data                          | String         | http request data      | -                 |\n| http.connect.timeout.milliseconds  | String         | http connect timeout   | 3000              |\n| http.read.timeout.milliseconds     | String         | http read timeout      | 5000              |\n| http.content.type                  | String         | http content type      | -                 |\n"
  },
  {
    "path": "docs/content/user-manual/configuration/spring-boot-starter.cn.md",
    "content": "+++\ntitle = \"Spring Boot Starter\"\nweight = 2\nchapter = true\n+++\n\n使用 Spring-boot 需在 pom.xml 文件中添加 elasticjob-spring-boot-starter 模块的依赖。\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-spring-boot-starter</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\n## 注册中心配置\n\n配置前缀：`elasticjob.reg-center`\n\n可配置属性：\n\n| 属性名                             | 是否必填 |\n|---------------------------------|:-----|\n| server-lists                    | 是    |\n| namespace                       | 是    |\n| base-sleep-time-milliseconds    | 否    |\n| max-sleep-time-milliseconds     | 否    |\n| max-retries                     | 否    |\n| session-timeout-milliseconds    | 否    |\n| connection-timeout-milliseconds | 否    |\n| digest                          | 否    |\n\n配置格式参考：\n\n**YAML**\n```yaml\nelasticjob:\n  regCenter:\n    serverLists: localhost:6181\n    namespace: elasticjob-springboot\n```\n\n**Properties**\n```\nelasticjob.reg-center.namespace=elasticjob-springboot\nelasticjob.reg-center.server-lists=localhost:6181\n```\n\n## 作业配置\n\n配置前缀：`elasticjob.jobs`\n\n可配置属性：\n\n| 属性名                               | 是否必填 |\n|-----------------------------------|:-----|\n| elasticJobClass / elasticJobType  | 是    |\n| cron                              | 否    |\n| timeZone                          | 否    |\n| jobBootstrapBeanName              | 否    |\n| sharding-total-count              | 是    |\n| sharding-item-parameters          | 否    |\n| job-parameter                     | 否    |\n| monitor-execution                 | 否    |\n| failover                          | 否    |\n| misfire                           | 否    |\n| max-time-diff-seconds             | 否    |\n| reconcile-interval-minutes        | 否    |\n| job-sharding-strategy-type        | 否    |\n| job-executor-service-handler-type | 否    |\n| job-error-handler-type            | 否    |\n| job-listener-types                | 否    |\n| description                       | 否    |\n| props                             | 否    |\n| disabled                          | 否    |\n| overwrite                         | 否    |\n\n**elasticJobClass 与 elasticJobType 互斥，每项作业只能有一种类型**\n\n如果配置了 cron 属性则为定时调度作业，Starter 会在应用启动时自动启动；\n否则为一次性调度作业，需要通过 jobBootstrapBeanName 指定 OneOffJobBootstrap Bean 的名称，\n在触发点注入 OneOffJobBootstrap 的实例并手动调用 execute() 方法。\n\n配置格式参考：\n\n**YAML**\n```yaml\nelasticjob:\n  jobs:\n    simpleJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.kernel.example.job.SpringBootSimpleJob\n      cron: 0/5 * * * * ?\n      timeZone: GMT+08:00\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n    scriptJob:\n      elasticJobType: SCRIPT\n      cron: 0/10 * * * * ?\n      shardingTotalCount: 3\n      props:\n        script.command.line: \"echo SCRIPT Job: \"\n    manualScriptJob:\n      elasticJobType: SCRIPT\n      jobBootstrapBeanName: manualScriptJobBean\n      shardingTotalCount: 9\n      props:\n        script.command.line: \"echo Manual SCRIPT Job: \"\n```\n\n**Properties**\n```\nelasticjob.jobs.simpleJob.elastic-job-class=org.apache.shardingsphere.elasticjob.kernel.example.job.SpringBootSimpleJob\nelasticjob.jobs.simpleJob.cron=0/5 * * * * ?\nelasticjob.jobs.simpleJob.timeZone=GMT+08:00\nelasticjob.jobs.simpleJob.sharding-total-count=3\nelasticjob.jobs.simpleJob.sharding-item-parameters=0=Beijing,1=Shanghai,2=Guangzhou\nelasticjob.jobs.scriptJob.elastic-job-type=SCRIPT\nelasticjob.jobs.scriptJob.cron=0/5 * * * * ?\nelasticjob.jobs.scriptJob.sharding-total-count=3\nelasticjob.jobs.scriptJob.props.script.command.line=echo SCRIPT Job:\nelasticjob.jobs.manualScriptJob.elastic-job-type=SCRIPT\nelasticjob.jobs.manualScriptJob.job-bootstrap-bean-name=manualScriptJobBean\nelasticjob.jobs.manualScriptJob.sharding-total-count=3\nelasticjob.jobs.manualScriptJob.props.script.command.line=echo Manual SCRIPT Job:\n```\n\n## 事件追踪配置\n\n配置前缀：`elasticjob.tracing`\n\n| 属性名             | 可选值 | 是否必填 | 描述    |\n|-----------------|:----|:-----|:------|\n| type            | RDB | 否    |       |\n| includeJobNames |     | 否    | 作业白名单 |\n| excludeJobNames |     | 否    | 作业黑名单 |\n\n**includeJobNames 与 excludeJobNames 互斥，事件追踪配置只能有一种属性**\n\n**includeJobNames 与 excludeJobNames 都为空时，默认为所有作业加载事件追踪**\n\n目前仅提供了 RDB 类型的事件追踪数据源实现。\nSpring IoC 容器中存在 DataSource 类型的 bean 且配置数据源类型为 RDB 时会自动配置事件追踪，无须显式创建。\n\n配置格式参考：\n\n**YAML**\n```yaml\nelasticjob:\n  tracing:\n    type: RDB\n    excludeJobNames: [ job-name-1, job-name-2 ]\n```\n\n**Properties**\n```\nelasticjob.tracing.type=RDB\nelasticjob.tracing.excludeJobNames=[ job-name ]\n```\n\n## 作业信息导出配置\n\n配置前缀：`elasticjob.dump`\n\n| 属性名     | 缺省值  | 是否必填 |\n|---------|:-----|:-----|\n| enabled | true | 否    |\n| port    |      | 是    |\n\nSpring Boot 提供了作业信息导出端口快速配置，只需在配置中指定导出所用的端口号即可启用导出功能。\n如果没有指定端口号，导出功能不会生效。\n\n配置参考：\n\n**YAML**\n```yaml\nelasticjob:\n  dump:\n    port: 9888\n```\n\n**Properties**\n```\nelasticjob.dump.port=9888\n```\n"
  },
  {
    "path": "docs/content/user-manual/configuration/spring-boot-starter.en.md",
    "content": "+++\ntitle = \"Spring Boot Starter\"\nweight = 2\nchapter = true\n+++\n\nTo use the Spring boot, user need to add the dependency of the `elasticjob-spring-boot-starter` module in the `pom.xml` file.\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-spring-boot-starter</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\n## Registry Center Configuration\n\nPrefix: `elasticjob.reg-center`\n\nConfiguration: \n\n| Property name                   | Required |\n|---------------------------------|:---------|\n| server-lists                    | Yes      |\n| namespace                       | Yes      |\n| base-sleep-time-milliseconds    | No       |\n| max-sleep-time-milliseconds     | No       |\n| max-retries                     | No       |\n| session-timeout-milliseconds    | No       |\n| connection-timeout-milliseconds | No       |\n| digest                          | No       |\n\nReference: \n\n**YAML**\n```yaml\nelasticjob:\n  regCenter:\n    serverLists: localhost:6181\n    namespace: elasticjob-springboot\n```\n\n**Properties**\n```\nelasticjob.reg-center.namespace=elasticjob-springboot\nelasticjob.reg-center.server-lists=localhost:6181\n```\n\n## Job Configuration\n\nPrefix: `elasticjob.jobs`\n\nConfiguration:\n\n| Property name                     | Required |\n|-----------------------------------|:---------|\n| elasticJobClass / elasticJobType  | Yes      |\n| cron                              | No       |\n| timeZone                          | No       |\n| jobBootstrapBeanName              | No       |\n| sharding-total-count              | Yes      |\n| sharding-item-parameters          | No       |\n| job-parameter                     | No       |\n| monitor-execution                 | No       |\n| failover                          | No       |\n| misfire                           | No       |\n| max-time-diff-seconds             | No       |\n| reconcile-interval-minutes        | No       |\n| job-sharding-strategy-type        | No       |\n| job-executor-service-handler-type | No       |\n| job-error-handler-type            | No       |\n| job-listener-types                | No       |\n| description                       | No       |\n| props                             | No       |\n| disabled                          | No       |\n| overwrite                         | No       |\n\n**\"elasticJobClass\" and \"elasticJobType\" are mutually exclusive.**\n\nIf cron was configured, the job will be created as a ScheduleJobBootstrap.\nThe Starter will start scheduling when application is ready.\nOtherwise, the job will be created as a OneOffJobBootstrap with a name specified by \"jobBootstrapBeanName\".\nIt requires manual injection and execution.\n\nReference: \n\n**YAML**\n```yaml\nelasticjob:\n  jobs:\n    simpleJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.kernel.example.job.SpringBootSimpleJob\n      cron: 0/5 * * * * ?\n      timeZone: GMT+08:00\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n    scriptJob:\n      elasticJobType: SCRIPT\n      cron: 0/10 * * * * ?\n      shardingTotalCount: 3\n      props:\n        script.command.line: \"echo SCRIPT Job: \"\n    manualScriptJob:\n      elasticJobType: SCRIPT\n      jobBootstrapBeanName: manualScriptJobBean\n      shardingTotalCount: 9\n      props:\n        script.command.line: \"echo Manual SCRIPT Job: \"\n```\n\n**Properties**\n```\nelasticjob.jobs.simpleJob.elastic-job-class=org.apache.shardingsphere.elasticjob.kernel.example.job.SpringBootSimpleJob\nelasticjob.jobs.simpleJob.cron=0/5 * * * * ?\nelasticjob.jobs.simpleJob.timeZone=GMT+08:00\nelasticjob.jobs.simpleJob.sharding-total-count=3\nelasticjob.jobs.simpleJob.sharding-item-parameters=0=Beijing,1=Shanghai,2=Guangzhou\nelasticjob.jobs.scriptJob.elastic-job-type=SCRIPT\nelasticjob.jobs.scriptJob.cron=0/5 * * * * ?\nelasticjob.jobs.scriptJob.sharding-total-count=3\nelasticjob.jobs.scriptJob.props.script.command.line=echo SCRIPT Job:\nelasticjob.jobs.manualScriptJob.elastic-job-type=SCRIPT\nelasticjob.jobs.manualScriptJob.job-bootstrap-bean-name=manualScriptJobBean\nelasticjob.jobs.manualScriptJob.sharding-total-count=3\nelasticjob.jobs.manualScriptJob.props.script.command.line=echo Manual SCRIPT Job:\n```\n\n## Event Trace Configuration\n\nPrefix: `elasticjob.tracing`\n\n| Property name   | Options | Required | Description       |\n|-----------------|:--------|:---------|:------------------|\n| type            | RDB     | No       |                   |\n| includeJobNames |         | No       | allow list of job |\n| excludeJobNames |         | No       | block list of job |\n\n**\"includeJobNames\" and \"excludeJobNames\" are mutually exclusive.**\n\n**Load all Job When \"includeJobNames\" and \"excludeJobNames\" are null.**\n\nRDB is the only supported type at present.\nIf Spring IoC container contained a bean of DataSource and RDB was set in configuration, an instance of TracingConfiguration will be created automatically.\n\nReference: \n\n**YAML**\n```yaml\nelasticjob:\n  tracing:\n    type: RDB\n    excludeJobNames: [ job-name-1, job-name-2 ]\n```\n\n**Properties**\n```\nelasticjob.tracing.type=RDB\nelasticjob.tracing.excludeJobNames=[ job-name ]\n```\n\n### Dump Job Info Configuration\n\nPrefix: `elasticjob.dump`\n\n| Property name | Default value | Required |\n|---------------|:--------------|:---------|\n| enabled       | true          | No       |\n| port          |               | Yes      |\n\nDesignate a port as dump port in configurations. The Spring Boot Starter will enable dumping automatically.\nIf the port for job dump was missing, dump won't be enabled.\n\nReference: \n\n**YAML**\n```yaml\nelasticjob:\n  dump:\n    port: 9888\n```\n\n**Properties**\n```\nelasticjob.dump.port=9888\n```\n"
  },
  {
    "path": "docs/content/user-manual/configuration/spring-namespace.cn.md",
    "content": "+++\ntitle = \"Spring 命名空间\"\nweight = 3\nchapter = true\n+++\n\n使用 Spring 命名空间需在 pom.xml 文件中添加 elasticjob-spring 模块的依赖。\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-spring-namespace</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\n命名空间：[http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd](http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd)\n\n## 注册中心配置\n\n\\<elasticjob:zookeeper />\n\n可配置属性：\n\n| 属性名                             | 是否必填 |\n|---------------------------------|:-----|\n| id                              | 是    |\n| server-lists                    | 是    |\n| namespace                       | 是    |\n| base-sleep-time-milliseconds    | 否    |\n| max-sleep-time-milliseconds     | 否    |\n| max-retries                     | 否    |\n| session-timeout-milliseconds    | 否    |\n| connection-timeout-milliseconds | 否    |\n| digest                          | 否    |\n\n## 作业配置\n\n\\<elasticjob:job />\n\n可配置属性：\n\n| 属性名                               | 是否必填 |\n|-----------------------------------|:-----|\n| id                                | 是    |\n| class                             | 否    |\n| job-ref                           | 否    |\n| registry-center-ref               | 是    |\n| tracing-ref                       | 否    |\n| cron                              | 是    |\n| timeZone                          | 否    |\n| sharding-total-count              | 是    |\n| sharding-item-parameters          | 否    |\n| job-parameter                     | 否    |\n| monitor-execution                 | 否    |\n| failover                          | 否    |\n| misfire                           | 否    |\n| max-time-diff-seconds             | 否    |\n| reconcile-interval-minutes        | 否    |\n| job-sharding-strategy-type        | 否    |\n| job-executor-service-handler-type | 否    |\n| job-error-handler-type            | 否    |\n| job-listener-types                | 否    |\n| description                       | 否    |\n| props                             | 否    |\n| disabled                          | 否    |\n| overwrite                         | 否    |\n\n## 事件追踪配置\n\n\\<elasticjob:rdb-tracing />\n\n可配置属性：\n\n| 属性名             | 类型         | 是否必填 | 缺省值 | 描述              |\n|-----------------|:-----------|:-----|:----|:----------------|\n| id              | String     | 是    |     | 事件追踪 Bean 主键    |\n| data-source-ref | DataSource | 是    |     | 事件追踪数据源 Bean 名称 |\n\n## 快照导出配置\n\n\\<elasticjob:snapshot />\n\n可配置属性：\n\n| 属性名                 | 类型     | 是否必填 | 缺省值 | 描述                                                             |\n|---------------------|:-------|:-----|:----|:---------------------------------------------------------------|\n| id                  | String | 是    |     | 监控服务在 Spring 容器中的主键                                            |\n| registry-center-ref | String | 是    |     | 注册中心 Bean 的引用，需引用 reg:zookeeper 的声明                            |\n| dump-port           | String | 是    |     | 导出作业信息数据端口<br />使用方法: echo \"dump@jobName\" \\| nc 127.0.0.1 9888 |\n"
  },
  {
    "path": "docs/content/user-manual/configuration/spring-namespace.en.md",
    "content": "+++\ntitle = \"Spring Namespace\"\nweight = 2\nchapter = true\n+++\n\nTo use the Spring namespace, user need to add the dependency of the `elasticjob-spring` module in the `pom.xml` file.\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-spring-namespace</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\nSpring namespace: [http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd](http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd)\n\n## Registry Center Configuration\n\n\\<elasticjob:zookeeper />\n\nConfiguration: \n\n| Name                            | Required |\n|---------------------------------|:---------|\n| id                              | Yes      |\n| server-lists                    | Yes      |\n| namespace                       | Yes      |\n| base-sleep-time-milliseconds    | No       |\n| max-sleep-time-milliseconds     | No       |\n| max-retries                     | No       |\n| session-timeout-milliseconds    | No       |\n| connection-timeout-milliseconds | No       |\n| digest                          | No       |\n\n## Job Configuration\n\n\\<elasticjob:job />\n\nConfiguration: \n\n| Name                              | Required |\n|-----------------------------------|:---------|\n| id                                | Yes      |\n| class                             | No       |\n| job-ref                           | No       |\n| registry-center-ref               | Yes      |\n| tracing-ref                       | No       |\n| cron                              | Yes      |\n| timeZone                          | No       |\n| sharding-total-count              | Yes      |\n| sharding-item-parameters          | No       |\n| job-parameter                     | No       |\n| monitor-execution                 | No       |\n| failover                          | No       |\n| misfire                           | No       |\n| max-time-diff-seconds             | No       |\n| reconcile-interval-minutes        | No       |\n| job-sharding-strategy-type        | No       |\n| job-executor-service-handler-type | No       |\n| job-error-handler-type            | No       |\n| description                       | No       |\n| props                             | No       |\n| disabled                          | No       |\n| overwrite                         | No       |\n\n## Event Tracing Configuration\n\n\\<elasticjob:rdb-tracing />\n\nConfiguration:\n\n| Name            | Data Type  | Required | Default Value | Description                                     |\n|-----------------|:-----------|:---------|:--------------|:------------------------------------------------|\n| id              | String     | Yes      |               | The bean's identify of the event tracing        |\n| data-source-ref | DataSource | No       |               | The bean's name of the event tracing DataSource |\n\n## Job Dump Configuration\n\n\\<elasticjob:snapshot />\n\nConfiguration: \n\n| Name                | Data Type | Required | Default Value | Description                                                                    |\n|---------------------|:----------|:---------|:--------------|:-------------------------------------------------------------------------------|\n| id                  | String    | Yes      |               | The identify of the monitoring service in the Spring container                 |\n| registry-center-ref | String    | Yes      |               | Registry center bean's reference, need to the statement of the `reg:zookeeper` |\n| dump-port           | String    | Yes      |               | Job dump port<br />usage: echo \"dump@jobName\" \\| nc 127.0.0.1 9888             |\n"
  },
  {
    "path": "docs/content/user-manual/operation/_index.cn.md",
    "content": "+++\npre = \"<b>4.1.3 </b>\"\ntitle = \"运维手册\"\nweight = 3\nchapter = true\n+++\n\n本章节是 ElasticJob 的运维参考手册。\n"
  },
  {
    "path": "docs/content/user-manual/operation/_index.en.md",
    "content": "+++\npre = \"<b>4.1.3 </b>\"\ntitle = \"Operation\"\nweight = 3\nchapter = true\n+++\n\nThis chapter is an operation manual for ElasticJob.\n"
  },
  {
    "path": "docs/content/user-manual/operation/deploy-guide.cn.md",
    "content": "+++\ntitle = \"部署指南\"\nweight = 1\nchapter = true\n+++\n\n## 应用部署\n\n1. 启动 ElasticJob 指定注册中心的 ZooKeeper。\n1. 运行包含 ElasticJob 和业务代码的 jar 文件。不限于 jar 或 war 的启动方式。\n1. 当作业服务器配置多网卡时，可通过设置系统变量 `elasticjob.preferred.network.interface` 指定网卡地址或\n `elasticjob.preferred.network.ip` 指定IP。 ElasticJob 默认获取网卡列表中第一个非回环可用 IPV4 地址。\n\n## 运维平台和 RESTFul API 部署(可选)\n\n1. 解压缩 `elasticjob-console-${version}.tar.gz` 并执行 `bin\\start.sh`。\n1. 打开浏览器访问 `http://localhost:8899/` 即可访问控制台。8899 为默认端口号，可通过启动脚本输入 `-p` 自定义端口号。\n1. 访问 RESTFul API 方法同控制台。\n1. `elasticjob-console-${version}.tar.gz` 可通过 `mvn install` 编译获取。\n"
  },
  {
    "path": "docs/content/user-manual/operation/deploy-guide.en.md",
    "content": "+++\ntitle = \"Deploy Guide\"\nweight = 1\nchapter = true\n+++\n\n## Application deployment\n\n1. Start the ZooKeeper of the ElasticJob designated registry.\n1. Run the jar file containing ElasticJob and business code. It is not limited to the startup mode of jar or war.\n1. When the job server is configured with multiple network cards, the network card address can be specified by setting the system variable `elasticjob.preferred.network.interface`\nor specify network addresses by setting the system variable `elasticjob.preferred.network.ip`. ElasticJob obtains the first non-loopback available IPV4 address in the network card list by default.\n\n## Operation and maintenance platform and RESTFul API deployment (optional)\n\n1. Unzip `elasticjob-console-${version}.tar.gz` and execute `bin\\start.sh`.\n1. Open the browser and visit `http://localhost:8899/` to access the console. 8899 is the default port number. You can customize the port number by entering `-p` through the startup script.\n1. The method of accessing RESTFul API is the same as the console.\n1. `elasticjob-console-${version}.tar.gz` can be obtained by compiling `mvn install`.\n\n"
  },
  {
    "path": "docs/content/user-manual/operation/dump.cn.md",
    "content": "+++\ntitle = \"导出作业信息\"\nweight = 2\nchapter = true\n+++\n\n使用 ElasticJob 过程中可能会碰到一些分布式问题，导致作业运行不稳定。\n\n由于无法在生产环境调试，通过 dump 命令可以把作业内部相关信息导出，方便开发者调试分析；\n另外为了不泄露隐私，已将相关信息中的 IP 地址以 ip1, ip2... 的形式过滤，可以在互联网上公开传输环境信息，便于进一步完善 ElasticJob。\n\n## 开启监听端口\n\n使用 Java API 开启导出端口配置请参见[Java API 作业信息导出配置](/cn/user-manual/elasticjob/configuration/java-api)。\n使用 Spring Boot Starter 开启导出端口配置请参见[Spring Boot Starter 作业信息导出配置](/cn/user-manual/elasticjob/configuration/java-api)。\n使用 Spring 命名空间 开启导出端口配置请参见[Spring 命名空间 作业信息导出配置](/cn/user-manual/elasticjob/configuration/spring-namespace)。\n\n## 执行导出命令\n\n导出命令完全参照 ZooKeeper 的四字命令理念。\n\n**导出至标准输出**\n\n```bash\necho \"dump@jobName\" | nc <任意一台作业服务器IP> 9888\n```\n\n![导出命令](https://shardingsphere.apache.org/elasticjob/current/img/dump/dump.jpg)\n\n**导出至文件**\n\n```bash\necho \"dump@jobName\" | nc <任意一台作业服务器IP> 9888 > job_debug.txt\n```\n"
  },
  {
    "path": "docs/content/user-manual/operation/dump.en.md",
    "content": "+++\ntitle = \"Dump Job Information\"\nweight = 2\nchapter = true\n+++\n\nUsing ElasticJob may meet some distributed problem which is not easy to observe.\n\nBecause of developer cannot debug in production environment, ElasticJob provide `dump` command to export job runtime information for debugging.\n\nFor security reason, the information dumped had already mask sensitive information, it instead of real IP address to `ip1`, `ip2` ...  \n\n## Open Listener Port\n\nTo open listener port using Java, refer to [Java API job information export configuration](/en/user-manual/elasticjob/configuration/java-api).\nTo open listener port using Spring Boot Starter, refer to [Spring Boot Starter job information export configuration](/en/user-manual/elasticjob/configuration/java-api).\nTo open listener port using Spring Namespace, refer to [Spring namespace job information export configuration](/en/user-manual/elasticjob/configuration/spring-namespace).\n\n## Execute Dump\n\n**Dump to stdout**\n\n```bash\necho \"dump@jobName\" | nc <job server IP address> 9888\n```\n\n![Dump](https://shardingsphere.apache.org/elasticjob/current/img/dump/dump.jpg)\n\n**Dump to file**\n\n```bash\necho \"dump@jobName\" | nc <job server IP address> 9888 > job_debug.txt\n```\n"
  },
  {
    "path": "docs/content/user-manual/operation/execution-monitor.cn.md",
    "content": "+++\ntitle = \"作业运行状态监控\"\nweight = 3\nchapter = true\n+++\n\n通过监听 ElasticJob 的 ZooKeeper 注册中心的几个关键节点即可完成作业运行状态监控功能。\n\n## 监听作业服务器存活\n\n监听 job_name\\instances\\job_instance_id 节点是否存在。该节点为临时节点，如果作业服务器下线，该节点将删除。\n"
  },
  {
    "path": "docs/content/user-manual/operation/execution-monitor.en.md",
    "content": "+++\ntitle = \"Execution Monitor\"\nweight = 3\nchapter = true\n+++\n\nBy monitoring several key nodes in the zookeeper registry of ElasticJob, the job running status monitoring function can be completed.\n\n## Monitoring job server alive\n\nListen for the existence of node job_name\\instances\\job_instance_id. This node is a temporary node. If the job server is offline, the node will be deleted.\n"
  },
  {
    "path": "docs/content/user-manual/operation/web-console.cn.md",
    "content": "+++\ntitle = \"运维平台\"\nweight = 4\nchapter = true\n+++\n\n解压缩 `elasticjob-console-${version}.tar.gz` 并执行 `bin\\start.sh`。\n打开浏览器访问 `http://localhost:8088/` 即可访问控制台。\n8088 为默认端口号，可通过启动脚本输入 `-p` 自定义端口号。\n\n## 登录\n\n控制台提供两种账户：管理员及访客。\n管理员拥有全部操作权限，访客仅拥有察看权限。\n默认管理员用户名和密码是 root/root，访客用户名和密码是 guest/guest，可通过 `conf\\application.properties` 修改管理员及访客用户名及密码。\n\n```\nauth.root_username=root\nauth.root_password=root\nauth.guest_username=guest\nauth.guest_password=guest\n```\n\n## Casdoor 登录\n\n控制台集成了[Casdoor](https://casdoor.org/)单点登录,用户可以选择 Casdoor 进行登录等一些列操作。\n\n步骤一: 部署 casdoor\nCasdoor的源代码托管在 GitHub: https://github.com/casdoor/casdoor \n\n启动模式有开发模式和生产模式,此处以开发模式为例,[更多详细](https://casdoor.org/docs/basic/server-installation)\n\n后端启动方式\n\n```bash\ngo run main.go\n```\n\n前端启动方式\n\n```bash\ncd web\nyarn install\nyarn start\n```\n\n步骤二:配置casdoor并得到所需的数据\n\n![casdoorConfig](https://shardingsphere.apache.org/elasticjob/current/img/casdoor/casdoorConfig.png)\n\n用红线指出来的是后端配置需要用到的,其中Redirect URLs取决于你要要callback的地址\n\n我们还需要根据所选cert到cert选项中找到对应的cert,如本例为cert-built-in,其中certificate也是我们所需要用到的。\n\n![cert](https://shardingsphere.apache.org/elasticjob/current/img/casdoor/cert.png)\n\n更多[casdoor文档](https://casdoor.org/docs/overview)\n\n步骤三:在ShardingSphere中进行配置\n\n在[sharingshphere-elasticjob-ui](https://github.com/apache/shardingsphere-elasticjob-ui)中的该application.properties进行配置\n\n![list](https://shardingsphere.apache.org/elasticjob/current/img/casdoor/list.png)\n\n将我们在casdoor获取的数据粘贴到相应位置即可如:\n\n![application](https://shardingsphere.apache.org/elasticjob/current/img/casdoor/application.png)\n\n这样我们就可以在shardingsphere-elasticjob-ui中使用casdoor了！更多功能详见[Casdoor](https://casdoor.org/)\n\n## 功能列表\n\n- 登录安全控制\n- 注册中心、事件追踪数据源管理\n- 快捷修改作业设置\n- 作业和服务器维度状态查看\n- 操作作业禁用\\启用、停止和删除等生命周期\n- 事件追踪查询\n\n## 设计理念\n\n运维平台和 ElasticJob 并无直接关系，是通过读取作业注册中心数据展现作业状态，或更新注册中心数据修改全局配置。\n\n控制台只能控制作业本身是否运行，但不能控制作业进程的启动，因为控制台和作业本身服务器是完全分离的，控制台并不能控制作业服务器。\n\n## 不支持项\n\n* 添加作业\n\n作业在首次运行时将自动添加。\nElasticJob 以 jar 方式启动，并无作业分发功能。\n"
  },
  {
    "path": "docs/content/user-manual/operation/web-console.en.md",
    "content": "+++\ntitle = \"Console\"\nweight = 4\nchapter = true\n+++\n\nUnzip `elasticjob-console-${version}.tar.gz` and execute `bin\\start.sh`.\nOpen the browser and visit `http://localhost:8899/` to access the console.\n8899 is the default port number. You can customize the port number by entering `-p` through the startup script.\n\n## Log in\n\nThe console provides two types of accounts: administrator and guest.\nThe administrator has all operation rights, and the visitors only have the viewing rights.\nThe default administrator user name and password are root/root，and the guest user name and password are guest/guest，You can modify the administrator and guest user names and passwords through `conf\\application.properties`.\n```\nauth.root_username=root\nauth.root_password=root\nauth.guest_username=guest\nauth.guest_password=guest\n```\n\n## Login with Casdoor\n\nThe console have integrated [Casdoor](https://casdoor.org/). We can choose it  for SSO.\n\nStep1: Deploy Casdoor\n\nCasdoor code in GitHub: https://github.com/casdoor/casdoor \n\nHere a example for development mode. [More](https://casdoor.org/docs/basic/server-installation)\n\nBackend\n\n```bash\ngo run main.go\n```\n\nFrontend\n\n```bash\ncd web\nyarn install\nyarn start\n```\n\nStep2:Configure Casdoor\n\n![casdoorConfig](https://shardingsphere.apache.org/elasticjob/current/img/casdoor/casdoorConfig.png)\n\nRedirectURLs is depend on what url you need redirect.The selected data will use in next.\n\n2.On the certificate editing page, you can see your `Certificate`\n\n![cert](https://shardingsphere.apache.org/elasticjob/current/img/casdoor/cert.png)\n\nStep3:Configure application in ShardingSphere\n\nFirst we need find the application.properties we need configure\n\n![list](https://shardingsphere.apache.org/elasticjob/current/img/casdoor/list.png)\n\nSecond we need copy the data in Casdoor application and paste them into application.\n\n![application](https://shardingsphere.apache.org/elasticjob/current/img/casdoor/application.png)\n\nNow we can use it\n\n## Function list\n\n- Login security control\n- Registration center, event tracking data source management\n- Quickly modify job settings\n- View job and server dimension status\n- Operational job disable/enable, stop and delete life cycle\n- Event tracking query\n\n## Design concept\n\nThe operation and maintenance platform has no direct relationship with ElasticJob. It displays the job status by reading the job registration center data, or updating the registration center data to modify the global configuration.\n\nThe console can only control whether the job itself is running, but it cannot control the start of the job process, because the console and the job server are completely separated, and the console cannot control the job server.\n\n## Unsupported item\n\n* Add assignment\n\nThe job will be automatically added the first time it runs.\nElasticJob is started as a jar and has no job distribution function.\n"
  },
  {
    "path": "docs/content/user-manual/usage/_index.cn.md",
    "content": "+++\npre = \"<b>4.1.1 </b>\"\ntitle = \"使用手册\"\nweight = 1\nchapter = true\n+++\n\n本章节将介绍 ElasticJob 相关使用。\n更多使用细节请参见[使用示例](https://github.com/apache/shardingsphere-elasticjob/tree/master/examples)。\n"
  },
  {
    "path": "docs/content/user-manual/usage/_index.en.md",
    "content": "+++\npre = \"<b>4.1.1 </b>\"\ntitle = \"Usage\"\nweight = 1\nchapter = true\n+++\n\nThis chapter will introduce the use of ElasticJob. \nPlease refer to [Example](https://github.com/apache/shardingsphere-elasticjob/tree/master/examples) for more details.\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-api/_index.cn.md",
    "content": "+++\ntitle = \"作业 API\"\nweight = 1\nchapter = true\n+++\n\nElasticJob 支持原生 Java、Spring Boot Starter 和 Spring 自定义命名空间 3 种使用方式。\n本章节将详细介绍他们的使用方式。\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-api/_index.en.md",
    "content": "+++\ntitle = \"Job API\"\nweight = 1\nchapter = true\n+++\n\nElasticJob can use for native Java, Spring Boot Starter and Spring namespace.\nThis chapter will introduce how to use them.\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-api/java-api.cn.md",
    "content": "+++\ntitle = \"使用 Java API\"\nweight = 2\nchapter = true\n+++\n\n## 作业配置\n\nElasticJob 采用构建器模式创建作业配置对象。\n代码示例如下：\n\n```java\n    JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myJob\", 3).cron(\"0/5 * * * * ?\").shardingItemParameters(\"0=Beijing,1=Shanghai,2=Guangzhou\").build();\n```\n\n## 作业启动\n\nElasticJob 调度器分为定时调度和一次性调度两种类型。\n每种调度器启动时均需要注册中心配置、作业对象（或作业类型）以及作业配置这 3 个参数。\n\n### 定时调度\n\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        // 调度基于 class 类型的作业\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createJobConfiguration()).schedule();\n        // 调度基于 type 类型的作业\n        new ScheduleJobBootstrap(createRegistryCenter(), \"MY_TYPE\", createJobConfiguration()).schedule();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"zk_host:2181\", \"elastic-job-demo\"));\n        regCenter.init();\n        return regCenter;\n    }\n    \n    private static JobConfiguration createJobConfiguration() {\n        // 创建作业配置\n        ...\n    }\n}\n```\n\n### 一次性调度\n\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        OneOffJobBootstrap jobBootstrap = new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createJobConfiguration());\n        // 可多次调用一次性调度\n        jobBootstrap.execute();\n        jobBootstrap.execute();\n        jobBootstrap.execute();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"zk_host:2181\", \"elastic-job-demo\"));\n        regCenter.init();\n        return regCenter;\n    }\n    \n    private static JobConfiguration createJobConfiguration() {\n        // 创建作业配置\n        ...\n    }\n}\n```\n\n## 配置作业导出端口\n\n使用 ElasticJob 过程中可能会碰到一些分布式问题，导致作业运行不稳定。\n\n由于无法在生产环境调试，通过 dump 命令可以把作业内部相关信息导出，方便开发者调试分析；\n\n导出命令的使用请参见[运维指南](/cn/user-manual/elasticjob/operation/dump)。\n\n以下示例用于展示如何通过 SnapshotService 开启用于导出命令的监听端口。\n\n```java\npublic class JobMain {\n    \n    public static void main(final String[] args) {\n        SnapshotService snapshotService = new SnapshotService(regCenter, 9888).listen();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // 创建注册中心\n    }\n}\n```\n\n\n## 配置错误处理策略\n\n使用 ElasticJob 过程中当作业发生异常后，可采用以下错误处理策略。\n\n| *错误处理策略名称* | *说明*                | *是否内置* | *是否默认* | *是否需要额外配置* |\n|------------|---------------------|--------|--------|------------|\n| 记录日志策略     | 记录作业异常日志，但不中断作业执行   | 是      | 是      |            |\n| 抛出异常策略     | 抛出系统异常并中断作业执行       | 是      |        |            |\n| 忽略异常策略     | 忽略系统异常且不中断作业执行      | 是      |        |            |\n| 邮件通知策略     | 发送邮件消息通知，但不中断作业执行   |        |        | 是          |\n| 企业微信通知策略   | 发送企业微信消息通知，但不中断作业执行 |        |        | 是          |\n| 钉钉通知策略     | 发送钉钉消息通知，但不中断作业执行   |        |        | 是          |\n\n### 记录日志策略\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  定时调度作业\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // 一次性调度作业\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // 创建定时作业配置， 并且使用记录日志策略\n        return JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"LOG\").build();\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // 创建一次性作业配置， 并且使用记录日志策略\n        return JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"LOG\").build();\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // 配置注册中心\n        ...\n    }\n}\n```\n\n### 抛出异常策略\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  定时调度作业\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // 一次性调度作业\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // 创建定时作业配置， 并且使用抛出异常策略\n        return JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"THROW\").build();\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // 创建一次性作业配置， 并且使用抛出异常策略\n        return JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"THROW\").build();\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // 配置注册中心\n        ...\n    }\n}\n```\n\n\n### 忽略异常策略\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  定时调度作业\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // 一次性调度作业\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // 创建定时作业配置， 并且使用忽略异常策略\n        return JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"IGNORE\").build();\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // 创建一次性作业配置， 并且使用忽略异常策略\n        return JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"IGNORE\").build();\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // 配置注册中心\n        ...\n    }\n}\n```\n\n### 邮件通知策略\n\n请参考 [这里](/cn/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#邮件通知策略) 了解更多。\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-email</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  定时调度作业\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // 一次性调度作业\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // 创建定时作业配置， 并且使用邮件通知策略\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"EMAIL\").build();\n        setEmailProperties(jobConfig);\n        return jobConfig;\n\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // 创建一次性作业配置， 并且使用邮件通知策略\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"EMAIL\").build();\n        setEmailProperties(jobConfig);\n        return jobConfig;\n    }\n\n    private static void setEmailProperties(final JobConfiguration jobConfig) {\n        // 设置邮件的配置\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.HOST, \"host\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.PORT, \"465\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.USERNAME, \"username\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.PASSWORD, \"password\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.FROM, \"from@xxx.xx\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.TO, \"to1@xxx.xx,to1@xxx.xx\");\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // 配置注册中心\n        ...\n    }\n}\n```\n\n### 企业微信通知策略\n\n请参考 [这里](/cn/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#企业微信通知策略) 了解更多。\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-wechat</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  定时调度作业\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // 一次性调度作业\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // 创建定时作业配置， 并且使用企业微信通知策略\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"WECHAT\").build();\n        setWechatProperties(jobConfig);\n        return jobConfig;\n\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // 创建一次性作业配置， 并且使用企业微信通知策略\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"WECHAT\").build();\n        setWechatProperties(jobConfig);\n        return jobConfig;\n    }\n\n    private static void setWechatProperties(final JobConfiguration jobConfig) {\n        // 设置企业微信的配置\n        jobConfig.getProps().setProperty(WechatPropertiesConstants.WEBHOOK, \"you_webhook\");\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // 配置注册中心\n        ...\n    }\n}\n```\n\n\n### 钉钉通知策略\n\n请参考 [这里](/cn/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#钉钉通知策略) 了解更多。\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  定时调度作业\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // 一次性调度作业\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // 创建定时作业配置， 并且使用企业微信通知策略\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"DINGTALK\").build();\n        setDingtalkProperties(jobConfig);\n        return jobConfig;\n\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // 创建一次性作业配置， 并且使用钉钉通知策略\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"DINGTALK\").build();\n        setDingtalkProperties(jobConfig);\n        return jobConfig;\n    }\n\n    private static void setDingtalkProperties(final JobConfiguration jobConfig) {\n        // 设置钉钉的配置\n        jobConfig.getProps().setProperty(DingtalkPropertiesConstants.WEBHOOK, \"you_webhook\");\n        jobConfig.getProps().setProperty(DingtalkPropertiesConstants.KEYWORD, \"you_keyword\");\n        jobConfig.getProps().setProperty(DingtalkPropertiesConstants.SECRET, \"you_secret\");\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // 配置注册中心\n        ...\n    }\n}\n```"
  },
  {
    "path": "docs/content/user-manual/usage/job-api/java-api.en.md",
    "content": "+++\ntitle = \"Use Java API\"\nweight = 2\nchapter = true\n+++\n\n## Job configuration\n\nElasticJob uses the builder mode to create job configuration objects.\nThe code example is as follows:\n\n```java\n    JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myJob\", 3).cron(\"0/5 * * * * ?\").shardingItemParameters(\"0=Beijing,1=Shanghai,2=Guangzhou\").build();\n```\n\n## Job start\n\nElasticJob scheduler is divided into two types: timed scheduling and one-time scheduling.\nEach scheduler needs three parameters: registry configuration, job object (or job type), and job configuration when it starts.\n\n### Timed scheduling\n\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        // Class-based Scheduling Jobs\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createJobConfiguration()).schedule();\n        // Type-based Scheduling Jobs\n        new ScheduleJobBootstrap(createRegistryCenter(), \"MY_TYPE\", createJobConfiguration()).schedule();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"zk_host:2181\", \"elastic-job-demo\"));\n        regCenter.init();\n        return regCenter;\n    }\n    \n    private static JobConfiguration createJobConfiguration() {\n        // Create job configuration\n        ...\n    }\n}\n```\n\n### One-Off scheduling\n\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        OneOffJobBootstrap jobBootstrap = new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createJobConfiguration());\n        // One-time scheduling can be called multiple times\n        jobBootstrap.execute();\n        jobBootstrap.execute();\n        jobBootstrap.execute();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"zk_host:2181\", \"elastic-job-demo\"));\n        regCenter.init();\n        return regCenter;\n    }\n    \n    private static JobConfiguration createJobConfiguration() {\n        // Create job configuration\n        ...\n    }\n}\n```\n\n## Job Dump\n\nUsing ElasticJob may meet some distributed problem which is not easy to observe.\n\nBecause of developer can not debug in production environment, ElasticJob provide `dump` command to export job runtime information for debugging.\n\nPlease refer to [Operation Manual](/en/user-manual/elasticjob/operation/dump) for more details.\n\nThe example below is how to configure spring namespace for open listener port to dump.\n\n```java\npublic class JobMain {\n    \n    public static void main(final String[] args) {\n        SnapshotService snapshotService = new SnapshotService(regCenter, 9888).listen();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // create registry center\n    }\n}\n```\n\n## Configuration error handler strategy\n\nIn the process of using ElasticJob, when the job is abnormal, the following error handling strategies can be used.\n\n| *Error handler strategy name*            | *Description*                                                 |  *Built-in*  | *Default*| *Extra config*   |\n| ---------------------------------------- | ------------------------------------------------------------- |  -------     |  --------|  --------------  |\n| Log Strategy                             | Log error and do not interrupt job                            |   Yes        |     Yes  |                  |\n| Throw Strategy                           | Throw system exception and interrupt job                      |   Yes        |          |                  |\n| Ignore Strategy                          | Ignore exception and do not interrupt job                     |   Yes        |          |                  |\n| Email Notification Strategy              | Send email message notification and do not interrupt job      |              |          |    Yes           |\n| Wechat Enterprise Notification Strategy  | Send wechat message notification and do not interrupt job     |              |          |    Yes           |\n| Dingtalk Notification Strategy           | Send dingtalk message notification and do not interrupt job   |              |          |    Yes           |\n\n### Log Strategy\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  Scheduling Jobs\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // One-time Scheduling Jobs\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // Create scheduling job configuration, and the use of log strategy\n        return JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"LOG\").build();\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // Create one-time job configuration, and the use of log strategy\n        return JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"LOG\").build();\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // create registry center\n        ...\n    }\n}\n```\n\n### Throw Strategy\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  Scheduling Jobs\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // One-time Scheduling Jobs\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // Create scheduling job configuration, and the use of throw strategy.\n        return JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"THROW\").build();\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // Create one-time job configuration, and the use of throw strategy\n        return JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"THROW\").build();\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // create registry center\n        ...\n    }\n}\n```\n\n\n### Ignore Strategy\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  Scheduling Jobs\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // One-time Scheduling Jobs\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // Create scheduling job configuration, and the use of ignore strategy.\n        return JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"IGNORE\").build();\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // Create one-time job configuration, and the use of ignore strategy.\n        return JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"IGNORE\").build();\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // create registry center.\n        ...\n    }\n}\n```\n\n### Email Notification Strategy\n\nPlease refer to [here](/en/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#email-notification-strategy) for more details.\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-email</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  Scheduling Jobs\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // One-time Scheduling Jobs\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // Create scheduling job configuration, and the use of email notification strategy.\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"EMAIL\").build();\n        setEmailProperties(jobConfig);\n        return jobConfig;\n\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // Create one-time job configuration, and the use of email notification strategy.\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"EMAIL\").build();\n        setEmailProperties(jobConfig);\n        return jobConfig;\n    }\n\n    private static void setEmailProperties(final JobConfiguration jobConfig) {\n        // Set the mail configuration.\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.HOST, \"host\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.PORT, \"465\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.USERNAME, \"username\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.PASSWORD, \"password\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.FROM, \"from@xxx.xx\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.TO, \"to1@xxx.xx,to1@xxx.xx\");\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // create registry center.\n        ...\n    }\n}\n```\n\n### Wechat Enterprise Notification Strategy\n\nPlease refer to [here](/en/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#wechat-enterprise-notification-strategy) for more details.\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-wechat</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  Scheduling Jobs.\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // One-time Scheduling Jobs.\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // Create scheduling job configuration, and the use of wechat enterprise notification strategy.\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"WECHAT\").build();\n        setWechatProperties(jobConfig);\n        return jobConfig;\n\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // Create one-time job configuration, and the use of wechat enterprise notification strategy.\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"WECHAT\").build();\n        setWechatProperties(jobConfig);\n        return jobConfig;\n    }\n\n    private static void setWechatProperties(final JobConfiguration jobConfig) {\n        // Set the configuration for the enterprise wechat.\n        jobConfig.getProps().setProperty(WechatPropertiesConstants.WEBHOOK, \"you_webhook\");\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // create registry center.\n        ...\n    }\n}\n```\n\n### Dingtalk Notification Strategy\n\nPlease refer to [here](/en/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#dingtalk-notification-strategy) for more details.\n\nMaven POM:\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n\n```java\npublic class JobDemo {\n    \n    public static void main(String[] args) {\n        //  Scheduling Jobs.\n        new ScheduleJobBootstrap(createRegistryCenter(), new MyJob(), createScheduleJobConfiguration()).schedule();\n        // One-time Scheduling Jobs.\n        new OneOffJobBootstrap(createRegistryCenter(), new MyJob(), createOneOffJobConfiguration()).execute();\n    }\n    \n    private static JobConfiguration createScheduleJobConfiguration() {\n        // Create scheduling job configuration, and the use of dingtalk  notification strategy.\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myScheduleJob\", 3).cron(\"0/5 * * * * ?\").jobErrorHandlerType(\"DINGTALK\").build();\n        setDingtalkProperties(jobConfig);\n        return jobConfig;\n\n    }\n\n    private static JobConfiguration createOneOffJobConfiguration() {\n        // Create one-time job configuration, and the use of dingtalk notification strategy.\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"myOneOffJob\", 3).jobErrorHandlerType(\"DINGTALK\").build();\n        setDingtalkProperties(jobConfig);\n        return jobConfig;\n    }\n\n    private static void setDingtalkProperties(final JobConfiguration jobConfig) {\n        // Set the configuration of the dingtalk.\n        jobConfig.getProps().setProperty(DingtalkPropertiesConstants.WEBHOOK, \"you_webhook\");\n        jobConfig.getProps().setProperty(DingtalkPropertiesConstants.KEYWORD, \"you_keyword\");\n        jobConfig.getProps().setProperty(DingtalkPropertiesConstants.SECRET, \"you_secret\");\n    }\n\n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        // create registry center.\n        ...\n    }\n}\n```"
  },
  {
    "path": "docs/content/user-manual/usage/job-api/job-interface.cn.md",
    "content": "+++\ntitle = \"作业开发\"\nweight = 1\nchapter = true\n+++\n\nElasticJob 的作业分类基于 class 和 type 两种类型。\n基于 class 的作业需要开发者自行通过实现接口的方式织入业务逻辑；\n基于 type 的作业则无需编码，只需要提供相应配置即可。\n\n基于 class 的作业接口的方法参数 `shardingContext` 包含作业配置、片和运行时信息。\n可通过 `getShardingTotalCount()`, `getShardingItem()` 等方法分别获取分片总数，运行在本作业服务器的分片序列号等。\n\nElasticJob 目前提供 Simple、Dataflow 这两种基于 class 的作业类型，并提供 Script、HTTP 这两种基于 type 的作业类型，用户可通过实现 SPI 接口自行扩展作业类型。\n\n## 简单作业\n\n意为简单实现，未经任何封装的类型。需实现 SimpleJob 接口。\n该接口仅提供单一方法用于覆盖，此方法将定时执行。\n与Quartz原生接口相似，但提供了弹性扩缩容和分片等功能。\n\n```java\npublic class MyElasticJob implements SimpleJob {\n    \n    @Override\n    public void execute(ShardingContext context) {\n        switch (context.getShardingItem()) {\n            case 0: \n                // do something by sharding item 0\n                break;\n            case 1: \n                // do something by sharding item 1\n                break;\n            case 2: \n                // do something by sharding item 2\n                break;\n            // case n: ...\n        }\n    }\n}\n```\n\n## 数据流作业\n\n用于处理数据流，需实现 DataflowJob 接口。\n该接口提供2个方法可供覆盖，分别用于抓取 (fetchData) 和处理 (processData) 数据。\n\n```java\npublic class MyElasticJob implements DataflowJob<Foo> {\n    \n    @Override\n    public List<Foo> fetchData(ShardingContext context) {\n        switch (context.getShardingItem()) {\n            case 0: \n                List<Foo> data = // get data from database by sharding item 0\n                return data;\n            case 1: \n                List<Foo> data = // get data from database by sharding item 1\n                return data;\n            case 2: \n                List<Foo> data = // get data from database by sharding item 2\n                return data;\n            // case n: ...\n        }\n    }\n    \n    @Override\n    public void processData(ShardingContext shardingContext, List<Foo> data) {\n        // process data\n        // ...\n    }\n}\n```\n\n***\n\n**流式处理**\n\n可通过属性配置 `streaming.process` 开启或关闭流式处理。\n\n如果开启流式处理，则作业只有在 fetchData 方法的返回值为 null 或集合容量为空时，才停止抓取，否则作业将一直运行下去；\n如果关闭流式处理，则作业只会在每次作业执行过程中执行一次 fetchData 和 processData 方法，随即完成本次作业。\n\n如果采用流式作业处理方式，建议 processData 在处理数据后更新其状态，避免 fetchData 再次抓取到，从而使得作业永不停止。\n\n## 脚本作业\n\n支持 shell，python，perl 等所有类型脚本。\n可通过属性配置 `script.command.line` 配置待执行脚本，无需编码。\n执行脚本路径可包含参数，参数传递完毕后，作业框架会自动追加最后一个参数为作业运行时信息。\n\n例如如下脚本：\n\n```bash\n#!/bin/bash\necho sharding execution context is $*\n```\n\n作业运行时将输出：\n\n```\nsharding execution context is {\"jobName\":\"scriptElasticDemoJob\",\"shardingTotalCount\":10,\"jobParameter\":\"\",\"shardingItem\":0,\"shardingParameter\":\"A\"}\n```\n\n## HTTP作业（3.0.0-beta 提供）\n\n可通过属性配置`http.url`,`http.method`,`http.data`等配置待请求的http信息。\n分片信息以Header形式传递，key为`shardingContext`，值为json格式。\n\n```java\n\npublic class HttpJobMain {\n    \n    public static void main(String[] args) {\n        \n        new ScheduleJobBootstrap(regCenter, \"HTTP\", JobConfiguration.newBuilder(\"javaHttpJob\", 1)\n                .setProperty(HttpJobProperties.URI_KEY, \"http://xxx.com/execute\")\n                .setProperty(HttpJobProperties.METHOD_KEY, \"POST\")\n                .setProperty(HttpJobProperties.DATA_KEY, \"source=ejob\")\n                .cron(\"0/5 * * * * ?\").shardingItemParameters(\"0=Beijing\").build()).schedule();\n    }\n}\n```\n```java\n@Controller\n@Slf4j\npublic class HttpJobController {\n    \n    @RequestMapping(path = \"/execute\", method = RequestMethod.POST)\n    public void execute(String source, @RequestHeader String shardingContext) {\n        log.info(\"execute from source : {}, shardingContext : {}\", source, shardingContext);\n    }\n}\n```\n\nexecute接口将输出：\n```\nexecute from source : ejob, shardingContext : {\"jobName\":\"scriptElasticDemoJob\",\"shardingTotalCount\":3,\"jobParameter\":\"\",\"shardingItem\":0,\"shardingParameter\":\"Beijing\"}\n```\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-api/job-interface.en.md",
    "content": "+++\ntitle = \"Job Development\"\nweight = 1\nchapter = true\n+++\n\nElasticJob has two kinds of job types: Class-based job and Type-based job.\nClass-based jobs require developers to weave business logic by implementing interfaces;\nType-based jobs don't need coding, just need to provide the corresponding configuration.\n\nThe method parameter `shardingContext` of the class-based job interface contains job configuration, slice and runtime information.\nThrough methods such as `getShardingTotalCount()`, `getShardingItem()`, user can obtain the total number of shards, the serial number of the shards running on the job server, etc.\n\nElasticJob provides two class-based job types which are `Simple` and `Dataflow`; and also provides a type-based job which is `Script`. Users can extend job types by implementing the SPI interface.\n\n## Simple Job\n\nIt means simple implementation, without any encapsulation type. Need to implement `SimpleJob` interface.\nThis interface only provides a single method for coverage, and this method will be executed periodically.\nIt is similar to Quartz's native interface, but provides functions such as elastic scaling and slice.\n\n```java\npublic class MyElasticJob implements SimpleJob {\n    \n    @Override\n    public void execute(ShardingContext context) {\n        switch (context.getShardingItem()) {\n            case 0: \n                // do something by sharding item 0\n                break;\n            case 1: \n                // do something by sharding item 1\n                break;\n            case 2: \n                // do something by sharding item 2\n                break;\n            // case n: ...\n        }\n    }\n}\n```\n\n## Dataflow Job\n\nFor processing data flow, need to implement `DataflowJob` interface.\nThis interface provides two methods for coverage, which are used to fetch (fetchData) and process (processData) data.\n\n```java\npublic class MyElasticJob implements DataflowJob<Foo> {\n    \n    @Override\n    public List<Foo> fetchData(ShardingContext context) {\n        switch (context.getShardingItem()) {\n            case 0: \n                List<Foo> data = // get data from database by sharding item 0\n                return data;\n            case 1: \n                List<Foo> data = // get data from database by sharding item 1\n                return data;\n            case 2: \n                List<Foo> data = // get data from database by sharding item 2\n                return data;\n            // case n: ...\n        }\n    }\n    \n    @Override\n    public void processData(ShardingContext shardingContext, List<Foo> data) {\n        // process data\n        // ...\n    }\n}\n```\n\n***\n\n**Streaming**\n\nStreaming can be enabled or disabled through the property `streaming.process`.\n\nIf streaming is enabled, the job will stop fetching data only when the return value of the `fetchData` method is null or the collection is empty, otherwise the job will continue to run;\nIf streaming is disabled, the job will execute the `fetchData` and `processData` methods only once during each job execution, and then the job will be completed immediately.\n\nIf use the streaming job to process data, it is recommended to update its status after the `processData` method being executed, to avoid being fetched again by the method `fetchData`, so that the job never stops.\n\n## Script job\n\nSupport all types of scripts such as `shell`, `python`, `perl`.\nThe script to be executed can be configured through the property `script.command.line`, without coding.\nThe script path can contain parameters, after the parameters are passed, the job framework will automatically append the last parameter as the job runtime information.\n\nThe script example is as follows:\n\n```bash\n#!/bin/bash\necho sharding execution context is $*\n```\n\nWhen the job runs, it will output:\n\n```\nsharding execution context is {\"jobName\":\"scriptElasticDemoJob\",\"shardingTotalCount\":10,\"jobParameter\":\"\",\"shardingItem\":0,\"shardingParameter\":\"A\"}\n```\n\n## HTTP job (Since 3.0.0-beta)\n\nThe http information to be requested can be configured through the properties of `http.url`, `http.method`, `http.data`, etc.\nSharding information is transmitted in the form of Header, the key is `shardingContext`, and the value is in json format.\n\n```java\n\npublic class HttpJobMain {\n    \n    public static void main(String[] args) {\n        \n        new ScheduleJobBootstrap(regCenter, \"HTTP\", JobConfiguration.newBuilder(\"javaHttpJob\", 1)\n                .setProperty(HttpJobProperties.URI_KEY, \"http://xxx.com/execute\")\n                .setProperty(HttpJobProperties.METHOD_KEY, \"POST\")\n                .setProperty(HttpJobProperties.DATA_KEY, \"source=ejob\")\n                .cron(\"0/5 * * * * ?\").shardingItemParameters(\"0=Beijing\").build()).schedule();\n    }\n}\n```\n```java\n@Controller\n@Slf4j\npublic class HttpJobController {\n    \n    @RequestMapping(path = \"/execute\", method = RequestMethod.POST)\n    public void execute(String source, @RequestHeader String shardingContext) {\n        log.info(\"execute from source : {}, shardingContext : {}\", source, shardingContext);\n    }\n}\n```\n\nWhen the job runs, it will output：\n```\nexecute from source : ejob, shardingContext : {\"jobName\":\"scriptElasticDemoJob\",\"shardingTotalCount\":3,\"jobParameter\":\"\",\"shardingItem\":0,\"shardingParameter\":\"Beijing\"}\n```\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-api/spring-boot-starter.cn.md",
    "content": "+++\ntitle = \"使用 Spring Boot Starter\"\nweight = 3\nchapter = true\n+++\n\nElasticJob 提供自定义的 Spring Boot Starter，可以与 Spring Boot 配合使用。\n基于 ElasticJob Spring Boot Starter 使用 ElasticJob ，用户无需手动创建 CoordinatorRegistryCenter、JobBootstrap 等实例，\n只需实现核心作业逻辑并辅以少量配置，即可利用轻量、无中心化的 ElasticJob 解决分布式调度问题。\n\n以下内容仅通过 Spring Boot 3 作为演示。 \n相关内容在 Spring Boot 2 上仍可能有效，但由于 Spring Boot 2 已经结束维护，不对 Spring Boot 2 做任何可用性假设。\n\n## 作业配置\n\n### 实现作业逻辑\n\n作业逻辑实现与 ElasticJob 的其他使用方式并没有较大的区别，只需将当前作业注册为 Spring 容器中的 bean。\n\n**线程安全问题**\n\nBean 默认是单例的，如果该作业实现会在同一个进程内被创建出多个 `JobBootstrap` 的实例，\n可以考虑设置 Scope 为 `prototype`。\n\n```java\n@Component\npublic class SpringBootDataflowJob implements DataflowJob<Foo> {\n    \n    @Override\n    public List<Foo> fetchData(final ShardingContext shardingContext) {\n        // 获取数据\n    }\n    \n    @Override\n    public void processData(final ShardingContext shardingContext, final List<Foo> data) {\n        // 处理数据\n    }\n}\n```\n\n### 配置协调服务与作业\n\n在配置文件中指定 ElasticJob 所使用的 Zookeeper。配置前缀为 `elasticjob.reg-center`。\n\n`elasticjob.jobs` 是一个 Map，key 为作业名称，value 为作业类型与配置。\nStarter 会根据该配置自动创建 `OneOffJobBootstrap` 或 `ScheduleJobBootstrap` 的实例并注册到 Spring 容器中。\n\n配置参考：\n\n```yaml\nelasticjob:\n  regCenter:\n    serverLists: localhost:6181\n    namespace: elasticjob-springboot\n  jobs:\n    dataflowJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob\n      cron: 0/5 * * * * ?\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n    scriptJob:\n      elasticJobType: SCRIPT\n      cron: 0/10 * * * * ?\n      shardingTotalCount: 3\n      props:\n        script.command.line: \"echo SCRIPT Job: \"\n```\n\n## 作业启动\n\n### 定时调度\n\n定时调度作业在 Spring Boot 应用程序启动完成后会自动启动，无需其他额外操作。\n\n### 一次性调度\n\n一次性调度的作业的执行权在开发者手中，开发者可以在需要调用作业的位置注入 `OneOffJobBootstrap`，\n通过 `execute()` 方法执行作业。\n\n用户不应该使用 `jakarta.annotation.Resource` 等部分违反 Spring Boot 最佳实践的注解来注入定义的一次性任务的 Spring Bean。\n\n`OneOffJobBootstrap` bean 的名称通过属性 jobBootstrapBeanName 配置，注入时需要指定依赖的 bean 名称。\n具体配置请参考[配置文档](/cn/user-manual/elasticjob/configuration/spring-boot-starter)。\n\n```yaml\nelasticjob:\n  jobs:\n    myOneOffJob:\n      elasticJobType: SCRIPT\n      jobBootstrapBeanName: myOneOffJobBean\n      shardingTotalCount: 9\n      props:\n        script.command.line: \"echo Manual SCRIPT Job: \"\n```\n\n```java\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.Objects;\n\n@RestController\npublic class OneOffJobController {\n    // 通过 \"@Autowired\" 注入\n    @Autowired\n    @Qualifier(\"myOneOffJobBean\")\n    private ObjectProvider<OneOffJobBootstrap> myOneOffJobProvider;\n\n    @GetMapping(\"/execute2\")\n    public String executeOneOffJob2() {\n        OneOffJobBootstrap myOneOffJob = myOneOffJobProvider.getIfAvailable();\n        Objects.requireNonNull(myOneOffJob);\n        myOneOffJob.execute();\n        return \"{\\\"msg\\\":\\\"OK\\\"}\";\n    }\n}\n```\n\n\n## 配置错误处理策略\n\n使用 ElasticJob 过程中当作业发生异常后，可采用以下错误处理策略。\n\n| *错误处理策略名称* | *说明*                | *是否内置* | *是否默认* | *是否需要额外配置* |\n|------------|---------------------|--------|--------|------------|\n| 记录日志策略     | 记录作业异常日志，但不中断作业执行   | 是      | 是      |            |\n| 抛出异常策略     | 抛出系统异常并中断作业执行       | 是      |        |            |\n| 忽略异常策略     | 忽略系统异常且不中断作业执行      | 是      |        |            |\n| 邮件通知策略     | 发送邮件消息通知，但不中断作业执行   |        |        | 是          |\n| 企业微信通知策略   | 发送企业微信消息通知，但不中断作业执行 |        |        | 是          |\n| 钉钉通知策略     | 发送钉钉消息通知，但不中断作业执行   |        |        | 是          |\n\n### 记录日志策略\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: LOG \n```\n\n### 抛出异常策略\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: THROW \n```\n\n\n### 忽略异常策略\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: IGNORE \n```\n\n### 邮件通知策略\n\n请参考 [这里](/cn/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#邮件通知策略) 了解更多。\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-email</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: EMAIL \n    props:\n      email:\n        host: host\n        port: 465\n        username: username\n        password: password\n        useSsl: true\n        subject: ElasticJob error message\n        from: from@xxx.xx\n        to: to1@xxx.xx,to2@xxx.xx\n        cc: cc@xxx.xx\n        bcc: bcc@xxx.xx\n        debug: false\n```\n\n### 企业微信通知策略\n\n请参考 [这里](/cn/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#企业微信通知策略) 了解更多。\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-wechat</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: WECHAT \n    props:\n      wechat:\n        webhook: you_webhook\n        connectTimeout: 3000\n        readTimeout: 5000\n```\n\n\n### 钉钉通知策略\n\n请参考 [这里](/cn/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#钉钉通知策略) 了解更多。\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: DINGTALK \n    props:\n      dingtalk:\n        webhook: you_webhook\n        keyword: you_keyword\n        secret: you_secret\n        connectTimeout: 3000\n        readTimeout: 5000\n```\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-api/spring-boot-starter.en.md",
    "content": "+++\ntitle = \"Use Spring Boot Starter\"\nweight = 3\nchapter = true\n+++\n\nElasticJob provides a customized Spring Boot Starter, which can be used in conjunction with Spring Boot.\nDevelopers are free from configuring CoordinatorRegistryCenter, JobBootstrap by using ElasticJob Spring Boot Starter.\nWhat developers need to solve distributed scheduling problem are job implementations with a little configuration.\n\nThe following content is only demonstrated through Spring Boot 3. \nThe relevant content may still be valid on Spring Boot 2, but since Spring Boot 2 has ended maintenance, no availability assumptions are made for Spring Boot 2.\n\n## Job configuration\n\n### Implements ElasticJob\n\nJob implementation is similar to other usage of ElasticJob. \nThe difference is that jobs will be registered into the Spring IoC container.\n\n**Thread-Safety Issue**\n\nBean is singleton by default. \nConsider setting Bean Scope to `prototype` if the instance of ElasticJob would be used by more than a JobBootstrap.\n\n```java\n@Component\npublic class SpringBootDataflowJob implements DataflowJob<Foo> {\n    \n    @Override\n    public List<Foo> fetchData(final ShardingContext shardingContext) {\n        // fetch data\n    }\n    \n    @Override\n    public void processData(final ShardingContext shardingContext, final List<Foo> data) {\n        // process data\n    }\n}\n```\n\n### Configure CoordinateRegistryCenter and Jobs\n\nConfigure the Zookeeper which will be used by ElasticJob via configuration files.\n\n`elasticjob.jobs` is a Map. Using key as job name. Specific job type and configuration in value.\nThe Starter will create instances of `OneOffJobBootstrap` or `ScheduleJobBootstrap` and register them into the Spring IoC container automatically. \n\nConfiguration reference:\n\n```yaml\nelasticjob:\n  regCenter:\n    serverLists: localhost:6181\n    namespace: elasticjob-springboot\n  jobs:\n    dataflowJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob\n      cron: 0/5 * * * * ?\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n    scriptJob:\n      elasticJobType: SCRIPT\n      cron: 0/10 * * * * ?\n      shardingTotalCount: 3\n      props:\n        script.command.line: \"echo SCRIPT Job: \"\n```\n\n## Job Start\n\n### Schedule Job\n\nJust start Spring Boot Starter directly. The schedule jobs will startup when the Spring Boot Application is started.\n\n### One-off Job\n\nWhen to execute OneOffJob is up to you. \nDevelopers can inject the `OneOffJobBootstrap` bean into where they plan to invoke.\nTrigger the job by invoking `execute()` method manually.\n\nUsers should not use annotations such as `jakarta.annotation.Resource` which partially violate Spring Boot best practices to inject Spring beans that define one-time tasks.\n\nThe bean name of `OneOffJobBootstrap` is specified by property \"jobBootstrapBeanName\",\nPlease refer to [Spring Boot Starter Configuration](/en/user-manual/elasticjob/configuration/spring-boot-starter).\n\n```yaml\nelasticjob:\n  jobs:\n    myOneOffJob:\n      elasticJobType: SCRIPT\n      jobBootstrapBeanName: myOneOffJobBean\n      shardingTotalCount: 9\n      props:\n        script.command.line: \"echo Manual SCRIPT Job: \"\n```\n\n```java\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.Objects;\n\n@RestController\npublic class OneOffJobController {\n    // Injection via \"@Autowired\"\n    @Autowired\n    @Qualifier(\"myOneOffJobBean\")\n    private ObjectProvider<OneOffJobBootstrap> myOneOffJobProvider;\n\n    @GetMapping(\"/execute2\")\n    public String executeOneOffJob2() {\n        OneOffJobBootstrap myOneOffJob = myOneOffJobProvider.getIfAvailable();\n        Objects.requireNonNull(myOneOffJob);\n        myOneOffJob.execute();\n        return \"{\\\"msg\\\":\\\"OK\\\"}\";\n    }\n}\n```\n\n## Configuration error handler strategy\n\nIn the process of using ElasticJob, when the job is abnormal, the following error handling strategies can be used.\n\n| *Error handler strategy name*           | *Description*                                               | *Built-in* | *Default* | *Extra config* |\n|-----------------------------------------|-------------------------------------------------------------|------------|-----------|----------------|\n| Log Strategy                            | Log error and do not interrupt job                          | Yes        | Yes       |                |\n| Throw Strategy                          | Throw system exception and interrupt job                    | Yes        |           |                |\n| Ignore Strategy                         | Ignore exception and do not interrupt job                   | Yes        |           |                |\n| Email Notification Strategy             | Send email message notification and do not interrupt job    |            |           | Yes            |\n| Wechat Enterprise Notification Strategy | Send wechat message notification and do not interrupt job   |            |           | Yes            |\n| Dingtalk Notification Strategy          | Send dingtalk message notification and do not interrupt job |            |           | Yes            |\n\n### Log Strategy\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: LOG \n```\n\n### Throw Strategy\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: THROW \n```\n\n### Ignore Strategy\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: IGNORE \n```\n\n### Email Notification Strategy\n\nPlease refer to [here](/en/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#email-notification-strategy) for more details.\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-email</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: EMAIL \n    props:\n      email:\n        host: host\n        port: 465\n        username: username\n        password: password\n        useSsl: true\n        subject: ElasticJob error message\n        from: from@xxx.xx\n        to: to1@xxx.xx,to2@xxx.xx\n        cc: cc@xxx.xx\n        bcc: bcc@xxx.xx\n        debug: false\n```\n\n### Wechat Enterprise Notification Strategy\n\nPlease refer to [here](/en/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#wechat-enterprise-notification-strategy) for more details.\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-wechat</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: WECHAT \n    props:\n      wechat:\n        webhook: you_webhook\n        connectTimeout: 3000\n        readTimeout: 5000\n```\n\n### Dingtalk Notification Strategy\n\nPlease refer to [here](/en/user-manual/elasticjob/configuration/built-in-strategy/error-handler/#dingtalk-notification-strategy) for more details.\n\nMaven POM:\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n    <version>${latest.release.version}</version>\n</dependency>\n```\n```yaml\nelasticjob:\n  regCenter:\n    ...\n  jobs:\n    ...\n    jobErrorHandlerType: DINGTALK \n    props:\n      dingtalk:\n        webhook: you_webhook\n        keyword: you_keyword\n        secret: you_secret\n        connectTimeout: 3000\n        readTimeout: 5000\n```\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-api/spring-namespace.cn.md",
    "content": "+++\ntitle = \"使用 Spring 命名空间\"\nweight = 4\nchapter = true\n+++\n\nElasticJob 提供自定义的 Spring 命名空间，可以与 Spring 容器配合使用。\n开发者能够便捷的在作业中通过依赖注入使用 Spring 容器管理的数据源等对象，并使用占位符从属性文件中取值。\n\n## 作业配置\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <!--配置作业注册中心 -->\n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"yourhost:2181\" namespace=\"my-job\" base-sleep-time-milliseconds=\"1000\" max-sleep-time-milliseconds=\"3000\" max-retries=\"3\" />\n    \n    <!-- 配置作业 Bean -->\n    <bean id=\"myJob\" class=\"xxx.MyJob\">\n        <property name=\"fooService\" ref=\"xxx.FooService\" />\n    </bean>\n    \n    <!-- 配置基于 class 的作业调度 -->   \n    <elasticjob:job id=\"${myJob.id}\" job-ref=\"myJob\" registry-center-ref=\"regCenter\" sharding-total-count=\"${myJob.shardingTotalCount}\" cron=\"${myJob.cron}\" />\n    \n    <!-- 配置基于 type 的作业调度 -->   \n    <elasticjob:job id=\"${myScriptJob.id}\" job-type=\"SCRIPT\" registry-center-ref=\"regCenter\" sharding-total-count=\"${myScriptJob.shardingTotalCount}\" cron=\"${myScriptJob.cron}\">\n        <props>\n            <prop key=\"script.command.line\">${myScriptJob.scriptCommandLine}</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n```\n\n## 作业启动\n\n### 定时调度\n\n将配置 Spring 命名空间的 xml 通过 Spring 启动，作业将自动加载。\n\n### 一次性调度\n\n一次性调度的作业的执行权在开发者手中，开发者可以在需要调用作业的位置注入 `OneOffJobBootstrap`，\n通过 `execute()` 方法执行作业。\n\n```xml\n\n<bean id=\"oneOffJob\" class=\"org.apache.shardingsphere.elasticjob.kernel.example.job.simple.SpringSimpleJob\"/>\n<elasticjob:job id=\"oneOffJobBean\" job-ref=\"oneOffJob\" ...  />\n```\n```java\npublic final class SpringMain {\n    public static void main(final String[] args) {\n        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(\"classpath:META-INF/application-context.xml\");\n        OneOffJobBootstrap oneOffJobBootstrap = context.getBean(\"oneOffJobBean\", OneOffJobBootstrap.class);\n        oneOffJobBootstrap.execute();\n    }\n}\n```\n\n## 配置作业导出端口\n\n使用 ElasticJob 过程中可能会碰到一些分布式问题，导致作业运行不稳定。\n\n由于无法在生产环境调试，通过 dump 命令可以把作业内部相关信息导出，方便开发者调试分析；\n\n导出命令的使用请参见[运维指南](/cn/user-manual/elasticjob/operation/dump)。\n\n以下示例用于展示如何通过 Spring 命名空间开启用于导出命令的监听端口。\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                         \">\n    <!--配置作业注册中心 -->\n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"yourhost:2181\" namespace=\"dd-job\" base-sleep-time-milliseconds=\"1000\" max-sleep-time-milliseconds=\"3000\" max-retries=\"3\" />\n    \n    <!--配置任务快照导出服务 -->\n    <elasticjob:snapshot id=\"jobSnapshot\" registry-center-ref=\"regCenter\" dump-port=\"9999\" />    \n</beans>\n```\n\n\n## 配置错误处理策略\n\n使用 ElasticJob 过程中当作业发生异常后，可采用以下错误处理策略。\n\n| *错误处理策略名称* | *说明*                | *是否内置* | *是否默认* | *是否需要额外配置* |\n|------------|---------------------|--------|--------|------------|\n| 记录日志策略     | 记录作业异常日志，但不中断作业执行   | 是      | 是      |            |\n| 抛出异常策略     | 抛出系统异常并中断作业执行       | 是      |        |            |\n| 忽略异常策略     | 忽略系统异常且不中断作业执行      | 是      |        |            |\n| 邮件通知策略     | 发送邮件消息通知，但不中断作业执行   |        |        | 是          |\n| 企业微信通知策略   | 发送企业微信消息通知，但不中断作业执行 |        |        | 是          |\n| 钉钉通知策略     | 发送钉钉消息通知，但不中断作业执行   |        |        | 是          |\n\n以下示例用于展示如何通过 Spring 命名空间配置错误处理策略。\n\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<elasticjob:job xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                         \">\n    <!-- 记录日志策略 -->\n    <elasticjob:job  ... job-error-handler-type=\"LOG\" />\n    \n    <!-- 抛出异常策略 -->\n    <elasticjob:job  ... job-error-handler-type=\"THROW\" />\n    \n    <!-- 忽略异常策略 -->\n    <elasticjob:job  ... job-error-handler-type=\"IGNORE\" />\n    \n    <!-- 邮件通知策略 -->    \n    <elasticjob:job ... job-error-handler-type=\"EMAIL\">\n        <props>\n            <prop key=\"email.host\">${host}</prop>\n            <prop key=\"email.port\">${port}</prop>\n            <prop key=\"email.username\">${username}</prop>\n            <prop key=\"email.password\">${password}</prop>\n            <prop key=\"email.useSsl\">${useSsl}</prop>\n            <prop key=\"email.subject\">${subject}</prop>\n            <prop key=\"email.from\">${from}</prop>\n            <prop key=\"email.to\">${to}</prop>\n            <prop key=\"email.cc\">${cc}</prop>\n            <prop key=\"email.bcc\">${bcc}</prop>\n            <prop key=\"email.debug\">${debug}</prop>\n        </props>\n    </elasticjob:job>\n    \n    <!-- 企业微信通知策略 -->\n    <elasticjob:job  ... job-error-handler-type=\"WECHAT\">\n        <props>\n            <prop key=\"wechat.webhook\">${webhook}</prop>\n            <prop key=\"wechat.connectTimeoutMilliseconds\">${connectTimeoutMilliseconds}</prop>\n            <prop key=\"wechat.readTimeoutMilliseconds\">${readTimeoutMilliseconds}</prop>\n        </props>\n    </elasticjob:job>\n    \n    <!-- 钉钉通知策略 -->\n    <elasticjob:job  ... job-error-handler-type=\"DINGTALK\">\n        <props>\n            <prop key=\"dingtalk.webhook\">${webhook}</prop>\n            <prop key=\"dingtalk.keyword\">${keyword}</prop>\n            <prop key=\"dingtalk.secret\">${secret}</prop>\n            <prop key=\"dingtalk.connectTimeoutMilliseconds\">${connectTimeoutMilliseconds}</prop>\n            <prop key=\"dingtalk.readTimeoutMilliseconds\">${readTimeoutMilliseconds}</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n```\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-api/spring-namespace.en.md",
    "content": "+++\ntitle = \"Use Spring Namespace\"\nweight = 4\nchapter = true\n+++\n\nElasticJob provides a custom Spring namespace, which can be used with the Spring.\nThrough the way of DI (Dependency Injection), developers can easily use data sources and other objects that managed by the Spring container in their jobs, and use placeholders to get values ​​from property files.\n\n## Job Configuration\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <!-- Configure registry center for job -->\n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"yourhost:2181\" namespace=\"my-job\" base-sleep-time-milliseconds=\"1000\" max-sleep-time-milliseconds=\"3000\" max-retries=\"3\" />\n    \n    <!-- Configure job java bean -->\n    <bean id=\"myJob\" class=\"xxx.MyJob\">\n        <property name=\"fooService\" ref=\"xxx.FooService\" />\n    </bean>\n    \n    <!-- Configure job scheduler base on java bean -->   \n    <elasticjob:job id=\"${myJob.id}\" job-ref=\"myJob\" registry-center-ref=\"regCenter\" sharding-total-count=\"${myJob.shardingTotalCount}\" cron=\"${myJob.cron}\" />\n    \n   <!-- Configure job scheduler base on type --> \n    <elasticjob:job id=\"${myScriptJob.id}\" job-type=\"SCRIPT\" registry-center-ref=\"regCenter\" sharding-total-count=\"${myScriptJob.shardingTotalCount}\" cron=\"${myScriptJob.cron}\">\n        <props>\n            <prop key=\"script.command.line\">${myScriptJob.scriptCommandLine}</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n```\n\n## Job Start\n\n### Schedule Job\n\nIf the Spring container start, the `XML` that configures the Spring namespace will be loaded, and the job will be automatically started.\n\n### One-off Job\n\nWhen to execute OneOffJob is up to you. \nDevelopers can inject the `OneOffJobBootstrap` bean into where they plan to invoke.\nTrigger the job by invoking `execute()` method manually.\n\n```xml\n\n<bean id=\"oneOffJob\" class=\"org.apache.shardingsphere.elasticjob.kernel.example.job.simple.SpringSimpleJob\"/>\n<elasticjob:job id=\"oneOffJobBean\" job-ref=\"oneOffJob\" ...  />\n```\n```java\npublic final class SpringMain {\n    public static void main(final String[] args) {\n        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(\"classpath:META-INF/application-context.xml\");\n        OneOffJobBootstrap oneOffJobBootstrap = context.getBean(\"oneOffJobBean\", OneOffJobBootstrap.class);\n        oneOffJobBootstrap.execute();\n    }\n}\n```\n\n## Job Dump\n\nUsing ElasticJob may meet some distributed problem which is not easy to observe.\n\nBecause of developer can not debug in production environment, ElasticJob provide `dump` command to export job runtime information for debugging.\n\nPlease refer to [Operation Manual](/en/user-manual/elasticjob/operation/dump) for more details.\n\nThe example below is how to configure SnapshotService for open listener port to dump.\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                         \">\n    <!--Create registry center -->\n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"yourhost:2181\" namespace=\"dd-job\" base-sleep-time-milliseconds=\"1000\" max-sleep-time-milliseconds=\"3000\" max-retries=\"3\" />\n    \n    <!--Configure the task snapshot export service -->\n    <elasticjob:snapshot id=\"jobSnapshot\" registry-center-ref=\"regCenter\" dump-port=\"9999\" />    \n</beans>\n```\n\n## Configuration error handler strategy\n\nIn the process of using ElasticJob, when the job is abnormal, the following error handling strategies can be used.\n\n| *Error handler strategy name*            | *Description*                                                 |  *Built-in*  | *Default*| *Extra config*   |\n| ---------------------------------------- | ------------------------------------------------------------- |  -------     |  --------|  --------------  |\n| Log Strategy                             | Log error and do not interrupt job                            |   Yes        |     Yes  |                  |\n| Throw Strategy                           | Throw system exception and interrupt job                      |   Yes        |          |                  |\n| Ignore Strategy                          | Ignore exception and do not interrupt job                     |   Yes        |          |                  |\n| Email Notification Strategy              | Send email message notification and do not interrupt job      |              |          |    Yes           |\n| Wechat Enterprise Notification Strategy  | Send wechat message notification and do not interrupt job     |              |          |    Yes           |\n| Dingtalk Notification Strategy           | Send dingtalk message notification and do not interrupt job   |              |          |    Yes           |\n\nThe following example shows how to configure the error-handling policy through the Spring namespace.\n\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                         \">\n    <!-- Log Strategy -->\n    <elasticjob:job  ... job-error-handler-type=\"LOG\" />\n    \n    <!-- Throw Strategy -->\n    <elasticjob:job  ... job-error-handler-type=\"THROW\" />\n    \n    <!-- Ignore Strategy -->\n    <elasticjob:job  ... job-error-handler-type=\"IGNORE\" />\n    \n    <!-- Email Notification Strategy  -->\n    <elasticjob:job ... job-error-handler-type=\"EMAIL\">\n        <props>\n            <prop key=\"email.host\">${host}</prop>\n            <prop key=\"email.port\">${port}</prop>\n            <prop key=\"email.username\">${username}</prop>\n            <prop key=\"email.password\">${password}</prop>\n            <prop key=\"email.useSsl\">${useSsl}</prop>\n            <prop key=\"email.subject\">${subject}</prop>\n            <prop key=\"email.from\">${from}</prop>\n            <prop key=\"email.to\">${to}</prop>\n            <prop key=\"email.cc\">${cc}</prop>\n            <prop key=\"email.bcc\">${bcc}</prop>\n            <prop key=\"email.debug\">${debug}</prop>\n        </props>\n    </elasticjob:job>\n    \n    <!-- Wechat Enterprise Notification Strategy -->\n    <elasticjob:job  ... job-error-handler-type=\"WECHAT\">\n        <props>\n            <prop key=\"wechat.webhook\">${webhook}</prop>\n            <prop key=\"wechat.connectTimeoutMilliseconds\">${connectTimeoutMilliseconds}</prop>\n            <prop key=\"wechat.readTimeoutMilliseconds\">${readTimeoutMilliseconds}</prop>\n        </props>\n    </elasticjob:job>\n    \n    <!-- Dingtalk Notification Strategy  -->\n    <elasticjob:job  ... job-error-handler-type=\"DINGTALK\">\n        <props>\n            <prop key=\"dingtalk.webhook\">${webhook}</prop>\n            <prop key=\"dingtalk.keyword\">${keyword}</prop>\n            <prop key=\"dingtalk.secret\">${secret}</prop>\n            <prop key=\"dingtalk.connectTimeoutMilliseconds\">${connectTimeoutMilliseconds}</prop>\n            <prop key=\"dingtalk.readTimeoutMilliseconds\">${readTimeoutMilliseconds}</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n```\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-listener/_index.cn.md",
    "content": "+++\ntitle = \"作业监听器\"\nweight = 2\nchapter = true\n+++\n\nElasticJob 提供作业监听器，用于在任务执行前和执行后执行监听的方法。\n监听器分为每台作业节点均执行的常规监听器和分布式场景中仅单一节点执行的分布式监听器。\n本章节将详细介绍他们的使用方式。\n\n在作业依赖（DAG）功能开发完成之后，可能会考虑删除作业监听器功能。\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-listener/_index.en.md",
    "content": "+++\ntitle = \"Job Listener\"\nweight = 2\nchapter = true\n+++\n\nElasticJob provides job listeners, which are used to perform monitoring methods before and after task execution.\nListeners are divided into regular listeners executed by each job node and distributed listeners executed by only a single node in a distributed scenario.\nThis chapter will introduce how to use them in detail.\n\nAfter the job dependency (DAG) function is developed, the job listener function may be considered to be deleted."
  },
  {
    "path": "docs/content/user-manual/usage/job-listener/java-api.cn.md",
    "content": "+++\ntitle = \"使用 Java API\"\nweight = 2\nchapter = true\n+++\n\n## 常规监听器\n\n```java\npublic class JobMain {\n    \n    public static void main(String[] args) {\n        new ScheduleJobBootstrap(createRegistryCenter(), createJobConfiguration()).schedule();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"zk_host:2181\", \"elastic-job-demo\"));\n        regCenter.init();\n        return regCenter;\n    }\n    \n    private static JobConfiguration createJobConfiguration() {\n        JobConfiguration jobConfiguration = JobConfiguration.newBuilder(\"test\", 2)\n                                .jobListenerTypes(\"simpleListener\", \"distributeListener\").build();\n    }\n}\n```\n\n## 分布式监听器\n\n```java\npublic class JobMain {\n    \n    public static void main(String[] args) {\n        new ScheduleJobBootstrap(createRegistryCenter(), createJobConfiguration()).schedule();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"zk_host:2181\", \"elastic-job-demo\"));\n        regCenter.init();\n        return regCenter;\n    }\n    \n    private static JobConfiguration createJobConfiguration() {\n        JobConfiguration jobConfiguration = JobConfiguration.newBuilder(\"test\", 2)\n                        .jobListenerTypes(\"simpleListener\", \"distributeListener\").build();\n    }\n}\n```\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-listener/java-api.en.md",
    "content": "+++\ntitle = \"Use Java API\"\nweight = 2\nchapter = true\n+++\n\n## Common Listener\n\n```java\npublic class JobMain {\n    \n    public static void main(String[] args) {\n        new ScheduleJobBootstrap(createRegistryCenter(), createJobConfiguration()).schedule();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"zk_host:2181\", \"elastic-job-demo\"));\n        regCenter.init();\n        return regCenter;\n    }\n    \n    private static JobConfiguration createJobConfiguration() {\n        JobConfiguration jobConfiguration = JobConfiguration.newBuilder(\"test\", 2)\n                                        .jobListenerTypes(\"simpleListener\", \"distributeListener\").build();\n    }\n}\n```\n\n## Distributed Listener\n\n```java\npublic class JobMain {\n    \n    public static void main(String[] args) {\n        new ScheduleJobBootstrap(createRegistryCenter(), createJobConfiguration()).schedule();\n    }\n    \n    private static CoordinatorRegistryCenter createRegistryCenter() {\n        CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"zk_host:2181\", \"elastic-job-demo\"));\n        regCenter.init();\n        return regCenter;\n    }\n    \n    private static JobConfiguration createJobConfiguration() {\n        JobConfiguration jobConfiguration = JobConfiguration.newBuilder(\"test\", 2)\n                                                .jobListenerTypes(\"simpleListener\", \"distributeListener\").build();\n    }\n}\n```\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-listener/listener-interface.cn.md",
    "content": "+++\ntitle = \"监听器开发\"\nweight = 1\nchapter = true\n+++\n\n## 常规监听器\n\n若作业处理作业服务器的文件，处理完成后删除文件，可考虑使用每个节点均执行清理任务。\n此类型任务实现简单，且无需考虑全局分布式任务是否完成，应尽量使用此类型监听器。\n\n```java\n\npublic class MyJobListener implements ElasticJobListener {\n    \n    @Override\n    public void beforeJobExecuted(ShardingContexts shardingContexts) {\n        // do something ...\n    }\n    \n    @Override\n    public void afterJobExecuted(ShardingContexts shardingContexts) {\n        // do something ...\n    }\n    \n    @Override\n    public String getType() {\n        return \"simpleJobListener\";\n    }\n}\n```\n\n## 分布式监听器\n\n若作业处理数据库数据，处理完成后只需一个节点完成数据清理任务即可。\n此类型任务处理复杂，需同步分布式环境下作业的状态同步，提供了超时设置来避免作业不同步导致的死锁，应谨慎使用。\n\n```java\n\npublic class MyDistributeOnceJobListener extends AbstractDistributeOnceElasticJobListener {\n    \n    private static final long startTimeoutMills = 3000;\n    private static final long completeTimeoutMills = 3000;\n\n    public MyDistributeOnceJobListener() {\n        super(startTimeoutMills, completeTimeoutMills);\n    }\n    \n    \n    @Override\n    public void doBeforeJobExecutedAtLastStarted(ShardingContexts shardingContexts) {\n        // do something ...\n    }\n    \n    @Override\n    public void doAfterJobExecutedAtLastCompleted(ShardingContexts shardingContexts) {\n        // do something ...\n    }\n    \n    @Override\n    public String getType() {\n        return \"distributeOnceJobListener\";\n    }\n}\n```\n\n## 添加SPI实现\n\n将JobListener实现添加至infra-common下resources/META-INF/services/org.apache.shardingsphere.elasticjob.infra.listener.ElasticJobListener\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-listener/listener-interface.en.md",
    "content": "+++\ntitle = \"Listener Development\"\nweight = 1\nchapter = true\n+++\n\n## Common Listener\n\nIf the job processes the files of the job server and deletes the files after the processing is completed, consider using each node to perform the cleaning task.\nThis type of task is simple to implement, and there is no need to consider whether the global distributed task is completed. You should try to use this type of listener.\n\n```java\n\npublic class MyJobListener implements ElasticJobListener {\n    \n    @Override\n    public void beforeJobExecuted(ShardingContexts shardingContexts) {\n        // do something ...\n    }\n    \n    @Override\n    public void afterJobExecuted(ShardingContexts shardingContexts) {\n        // do something ...\n    }\n   \n    @Override\n    public String getType() {\n        return \"simpleJobListener\";\n    }\n}\n```\n\n## Distributed Listener\n\nIf the job processes database data, only one node needs to complete the data cleaning task after the processing is completed.\nThis type of task is complicated to process and needs to synchronize the status of the job in a distributed environment. Timeout settings are provided to avoid deadlocks caused by job out of sync. It should be used with caution.\n\n```java\n\npublic class MyDistributeOnceJobListener extends AbstractDistributeOnceElasticJobListener {\n    \n    public TestDistributeOnceElasticJobListener(long startTimeoutMills, long completeTimeoutMills) {\n        super(startTimeoutMills, completeTimeoutMills);\n    }\n    \n    @Override\n    public void doBeforeJobExecutedAtLastStarted(ShardingContexts shardingContexts) {\n        // do something ...\n    }\n    \n    @Override\n    public void doAfterJobExecutedAtLastCompleted(ShardingContexts shardingContexts) {\n        // do something ...\n    }\n    \n    @Override\n    public String getType() {\n        return \"distributeOnceJobListener\";\n    }\n}\n```\n\n## Add SPI implementation\n\nPut JobListener implementation to module infra-common, resources/META-INF/services/org.apache.shardingsphere.elasticjob.infra.listener.ElasticJobListener\n\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-listener/spring-namespace.cn.md",
    "content": "+++\ntitle = \"使用 Spring 命名空间\"\nweight = 3\nchapter = true\n+++\n\n## 监听器配置\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <!--配置作业注册中心 -->\n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"yourhost:2181\" namespace=\"my-job\" base-sleep-time-milliseconds=\"1000\" max-sleep-time-milliseconds=\"3000\" max-retries=\"3\" />\n    \n    <!-- 配置作业 Bean -->\n    <bean id=\"myJob\" class=\"xxx.MyJob\" />\n    \n    <elasticjob:job id=\"${myJob.id}\" job-ref=\"myJob\" registry-center-ref=\"regCenter\" sharding-total-count=\"3\" cron=\"0/1 * * * * ?\" job-listener-types=\"simpleJobListener,distributeOnceJobListener\">\n    </elasticjob:job>\n</beans>\n```\n\n## 作业启动\n\n将配置 Spring 命名空间的 xml 通过 Spring 启动，作业将自动加载。\n"
  },
  {
    "path": "docs/content/user-manual/usage/job-listener/spring-namespace.en.md",
    "content": "+++\ntitle = \"Use Spring Namespace\"\nweight = 3\nchapter = true\n+++\n\n## Listener configuration\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <!-- Configuration job registration center -->\n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"yourhost:2181\" namespace=\"my-job\" base-sleep-time-milliseconds=\"1000\" max-sleep-time-milliseconds=\"3000\" max-retries=\"3\" />\n    \n    <!-- Configuration Job Bean -->\n    <bean id=\"myJob\" class=\"xxx.MyJob\" />\n    \n    <elasticjob:job id=\"${myJob.id}\" job-ref=\"myJob\" registry-center-ref=\"regCenter\" sharding-total-count=\"3\" cron=\"0/1 * * * * ?\" job-listener-types=\"simpleJobListener,distributeOnceJobListener\">\n    </elasticjob:job>\n</beans>\n```\n\n## Job start\n\nThe xml that configures the Spring namespace is started through Spring, and the job will be automatically loaded.\n\n"
  },
  {
    "path": "docs/content/user-manual/usage/operation-api/_index.cn.md",
    "content": "+++\ntitle = \"操作 API\"\nweight = 4\nchapter = true\n+++\n\nElasticJob 提供了 Java API，可以通过直接对注册中心进行操作的方式控制作业在分布式环境下的生命周期。\n\n该模块目前仍处于孵化状态。可能的依赖配置如下，\n\n```xml\n<dependency>\n  <groupId>org.apache.shardingsphere.elasticjob</groupId>\n  <artifactId>elasticjob-lifecycle</artifactId>\n  <version>${elasticjob.version}</version>\n</dependency>\n```\n\n## 配置类 API\n\n类名称：`org.apache.shardingsphere.elasticjob.lifecycle.api.JobConfigurationAPI`\n\n### 获取作业配置\n\n方法签名：`JobConfigurationPOJO getJobConfiguration(String jobName)`\n\n* **Parameters:** \n  * jobName — 作业名称\n\n* **Returns:** 作业配置对象\n\n### 更新作业配置\n\n方法签名：`void updateJobConfiguration(JobConfigurationPOJO jobConfig)`\n\n* **Parameters:** \n  * jobConfig — 作业配置对象\n\n### 删除作业设置 \n\n方法签名：`void removeJobConfiguration(String jobName)`\n\n* **Parameters:** \n  * jobName — 作业名称\n\n## 操作类 API\n\n类名称：`org.apache.shardingsphere.elasticjob.lifecycle.api.JobOperateAPI`\n\n### 触发作业执行\n\n作业在不与当前运行中作业冲突的情况下才会触发执行，并在启动后自动清理此标记。\n\n方法签名：`void trigger(String jobName)`\n\n* **Parameters:**\n  * jobName — 作业名称\n\n### 禁用作业\n\n禁用作业将会导致分布式的其他作业触发重新分片。\n\n方法签名：`void disable(String jobName, String serverIp)`\n\n* **Parameters:**\n  * jobName — 作业名称\n  * serverIp — 作业服务器 IP 地址\n\n### 启用作业\n\n方法签名：`void enable(String jobName, String serverIp)`\n\n* **Parameters:**\n  * jobName — 作业名称\n  * serverIp — 作业服务器 IP 地址\n\n### 停止调度作业\n\n方法签名：`void shutdown(String jobName, String serverIp)`\n\n* **Parameters:**\n  * jobName — 作业名称\n  * serverIp — 作业服务器IP地址\n\n### 删除作业\n\n方法签名：`void remove(String jobName, String serverIp)`\n\n* **Parameters:**\n  * jobName — 作业名称\n  * serverIp — 作业服务器IP地址\n\n### Dump 作业\n\n方法签名：`String dump(String jobName, String instanceIp, int dumpPort) throws IOException`\n\n* **Parameters:**\n  * jobName — 作业名称\n  * serverIp — 作业服务器IP地址\n  * dumpPort — Dump port \n\n## 操作分片的 API\n\n类名称：`org.apache.shardingsphere.elasticjob.lifecycle.api.ShardingOperateAPI`\n\n### 禁用作业分片\n\n方法签名：`void disable(String jobName, String item)`\n\n* **Parameters:**\n  * jobName — 作业名称\n  * item — 作业分片项\n\n### 启用作业分片\n\n方法签名：`void enable(String jobName, String item)`\n\n* **Parameters:**\n  * jobName — 作业名称\n  * item — 作业分片项\n\n## 作业统计 API\n\n类名称：`org.apache.shardingsphere.elasticjob.lifecycle.api.JobStatisticsAPI`\n\n### 获取作业总数\n\n方法签名：`int getJobsTotalCount()`\n\n* **Returns:** 作业总数\n\n### 获取作业简明信息\n\n方法签名：`JobBriefInfo getJobBriefInfo(String jobName)`\n\n* **Parameters:**\n  * jobName — 作业名称\n \n* **Returns:** 作业简明信息\n\n### 获取所有作业简明信息\n\n方法签名：`Collection<JobBriefInfo> getAllJobsBriefInfo()`\n\n* **Returns:** 作业简明信息集合\n\n### 获取该 IP 下所有作业简明信息\n\n方法签名：`Collection<JobBriefInfo> getJobsBriefInfo(String ip)`\n\n* **Parameters:**\n  * ip — 服务器 IP\n \n* **Returns:** 作业简明信息集合\n\n## 作业服务器状态展示 API\n\n类名称：`org.apache.shardingsphere.elasticjob.lifecycle.api.ServerStatisticsAPI`\n\n### 获取作业服务器总数\n\n方法签名：`int getServersTotalCount()`\n\n* **Returns:** 作业服务器总数\n\n### 获取所有作业服务器简明信息\n\n方法签名：`Collection<ServerBriefInfo> getAllServersBriefInfo()`\n\n* **Returns:** 作业服务器简明信息集合\n\n## 作业分片状态展示 API\n\n类名称：`org.apache.shardingsphere.elasticjob.lifecycle.api.ShardingStatisticsAPI`\n\n### 获取作业分片信息集合\n\n方法签名：`Collection<ShardingInfo> getShardingInfo(String jobName)`\n\n* **Parameters:**\n  * jobName — 作业名称\n \n* **Returns:** 作业分片信息集合\n"
  },
  {
    "path": "docs/content/user-manual/usage/operation-api/_index.en.md",
    "content": "+++\ntitle = \"Operation API\"\nweight = 4\nchapter = true\n+++\n\nElasticJob provides a Java API, which can control the life cycle of jobs in a distributed environment by directly operating the registry.\n\nThe module is still in incubation. Possible dependency configurations are as follows,\n\n```xml\n<dependency>\n  <groupId>org.apache.shardingsphere.elasticjob</groupId>\n  <artifactId>elasticjob-lifecycle</artifactId>\n  <version>${elasticjob.version}</version>\n</dependency>\n```\n\n## Configuration API\n\nClass name: `org.apache.shardingsphere.elasticjob.lifecycle.api.JobConfigurationAPI`\n\n### Get job configuration\n\nMethod signature：`JobConfigurationPOJO getJobConfiguration(String jobName)`\n\n* **Parameters:** \n  * jobName — Job name\n\n* **Returns:** Job configuration object\n\n### Update job configuration\n\nMethod signature：`void updateJobConfiguration(JobConfigurationPOJO jobConfig)`\n\n* **Parameters:** \n  * jobConfig — Job configuration object\n\n### Remove job configuration \n\nMethod signature：`void removeJobConfiguration(String jobName)`\n\n* **Parameters:** \n  * jobName — Job name\n\n## Operation API\n\nClass name：`org.apache.shardingsphere.elasticjob.lifecycle.api.JobOperateAPI`\n\n### Trigger job execution\n\nThe job will only trigger execution if it does not conflict with the currently running job, and this flag will be automatically cleared after it is started.\n\nMethod signature：`void trigger(String jobName)`\n\n* **Parameters:**\n  * jobName — Job name\n\n### Disable job\n\nDisabling a job will cause other distributed jobs to trigger resharding.\n\nMethod signature：`void disable(String jobName, String serverIp)`\n\n* **Parameters:**\n  * jobName — Job name\n  * serverIp — job server IP address\n\n### Enable job\n\nMethod signature：`void enable(String jobName, String serverIp)`\n\n* **Parameters:**\n  * jobName — Job name\n  * serverIp — job server IP address\n\n### Shutdown scheduling job\n\nMethod signature：`void shutdown(String jobName, String serverIp)`\n\n* **Parameters:**\n  * jobName — Job name\n  * serverIp — IP address of the job server\n\n### Remove job\n\nMethod signature：`void remove(String jobName, String serverIp)`\n\n* **Parameters:**\n  * jobName — Job name\n  * serverIp — IP address of the job server\n\n### Dump job\n\nMethod signature：`String dump(String jobName, String instanceIp, int dumpPort) throws IOException`\n\n* **Parameters:**\n  * jobName — Job name\n  * serverIp — IP address of the job server\n  * dumpPort — Dump port\n\n## Operate sharding API\n\nClass name：`org.apache.shardingsphere.elasticjob.lifecycle.api.ShardingOperateAPI`\n\n### Disable job sharding\n\nMethod signature：`void disable(String jobName, String item)`\n\n* **Parameters:**\n  * jobName — Job name\n  * item — Job sharding item\n\n### Enable job sharding\n\nMethod signature：`void enable(String jobName, String item)`\n\n* **Parameters:**\n  * jobName — Job name\n  * item — Job sharding item\n\n## Job statistics API\n\nClass name：`org.apache.shardingsphere.elasticjob.lifecycle.api.JobStatisticsAPI`\n\n### Get the total count of jobs\n\nMethod signature：`int getJobsTotalCount()`\n\n* **Returns:** the total count of jobs\n\n### Get brief job information\n\nMethod signature：`JobBriefInfo getJobBriefInfo(String jobName)`\n\n* **Parameters:**\n  * jobName — Job name\n \n* **Returns:** The brief job information\n\n### Get brief information about all jobs.\n\nMethod signature：`Collection<JobBriefInfo> getAllJobsBriefInfo()`\n\n* **Returns:** Brief collection of all job information\n\n### Get brief information of all jobs under this IP\n\nMethod signature：`Collection<JobBriefInfo> getJobsBriefInfo(String ip)`\n\n* **Parameters:**\n  * ip — server IP\n \n* **Returns:** Brief collection of job information\n\n## Job server status display API\n\nClass name：`org.apache.shardingsphere.elasticjob.lifecycle.api.ServerStatisticsAPI`\n\n### Total count of job servers\n\nMethod signature：`int getServersTotalCount()`\n\n* **Returns:** Get the total count of job servers\n\n### Get brief information about all job servers\n\nMethod signature：`Collection<ServerBriefInfo> getAllServersBriefInfo()`\n\n* **Returns:** Brief collection of job information\n\n## Job sharding status display API\n\nClass name：`org.apache.shardingsphere.elasticjob.lifecycle.api.ShardingStatisticsAPI`\n\n### Get job sharding information collection\n\nMethod signature：`Collection<ShardingInfo> getShardingInfo(String jobName)`\n\n* **Parameters:**\n  * jobName — Job name\n \n* **Returns:** The collection of job sharding information\n"
  },
  {
    "path": "docs/content/user-manual/usage/tracing/_index.cn.md",
    "content": "+++\ntitle = \"事件追踪\"\nweight = 3\nchapter = true\n+++\n\nElasticJob 提供了事件追踪功能，可通过事件订阅的方式处理调度过程的重要事件，用于查询、统计和监控。\n目前提供了基于关系型数据库的事件订阅方式记录事件，开发者也可以通过 SPI 自行扩展。\n"
  },
  {
    "path": "docs/content/user-manual/usage/tracing/_index.en.md",
    "content": "+++\ntitle = \"Tracing\"\nweight = 3\nchapter = true\n+++\n\nElasticJob provides a tracing function, which can handle important events in the scheduling process through event subscription for query, statistics and monitor.\nNow, the event subscription based on relation database is provided to record events, and developers can also extend it through SPI.\n"
  },
  {
    "path": "docs/content/user-manual/usage/tracing/java-api.cn.md",
    "content": "+++\ntitle = \"使用 Java API\"\nweight = 1\nchapter = true\n+++\n\nElasticJob 在配置中提供了 TracingConfiguration，目前支持数据库方式配置。\n开发者也可以通过 SPI 自行扩展。\n\n```java\n    // 初始化数据源\n    DataSource dataSource = ...;\n    // 定义日志数据库事件溯源配置\n    TracingConfiguration tracingConfig = new TracingConfiguration<>(\"RDB\", dataSource);\n    // 初始化注册中心\n    CoordinatorRegistryCenter regCenter = ...;\n    // 初始化作业配置\n    JobConfiguration jobConfig = ...;\n    jobConfig.getExtraConfigurations().add(tracingConfig);\n    new ScheduleJobBootstrap(regCenter, jobConfig).schedule();\n```\n"
  },
  {
    "path": "docs/content/user-manual/usage/tracing/java-api.en.md",
    "content": "+++\ntitle = \"Use Java API\"\nweight = 1\nchapter = true\n+++\n\nElasticJob currently provides `TracingConfiguration` based on database in the configuration.\nDevelopers can also extend it through SPI.\n\n```java\n    // init DataSource\n    DataSource dataSource = ...;\n    // define tracing configuration based on relation database\n    TracingConfiguration tracingConfig = new TracingConfiguration<>(\"RDB\", dataSource);\n    // init registry center\n    CoordinatorRegistryCenter regCenter = ...;\n    // init job configuration\n    JobConfiguration jobConfig = ...;\njobConfig.getExtraConfigurations().add(tracingConfig);\n    new ScheduleJobBootstrap(regCenter, jobConfig).schedule();\n```\n"
  },
  {
    "path": "docs/content/user-manual/usage/tracing/spring-boot-starter.cn.md",
    "content": "+++\ntitle = \"使用 Spring Boot Starter\"\nweight = 2\nchapter = true\n+++\n\nElasticJob 的 Spring Boot Starter 集成了 TracingConfiguration 自动配置，\n开发者只需注册一个 DataSource 到 Spring 容器中并在配置文件指定事件追踪数据源类型，\nStarter 就会自动创建一个 TracingConfiguration 实例并注册到 Spring 容器中。\n\n## 引入 Maven 依赖\n\n引入 spring-boot-starter-jdbc 注册数据源或自行创建一个 DataSource Bean。\n\n```xml\n<dependency>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-jdbc</artifactId>\n    <version>${springboot.version}</version>\n</dependency>\n```\n\n## 配置\n\n```yaml\nspring:\n  datasource:\n    url: jdbc:h2:mem:job_event_storage\n    driver-class-name: org.h2.Driver\n    username: sa\n    password:\n\nelasticjob:\n  tracing:\n    type: RDB\n```\n\n## 作业启动\n\n指定事件追踪数据源类型为 RDB，TracingConfiguration 会自动注册到容器中，如果与 elasticjob-spring-boot-starter 配合使用，\n开发者无需进行其他额外的操作，作业启动器会自动使用创建的 TracingConfiguration。\n"
  },
  {
    "path": "docs/content/user-manual/usage/tracing/spring-boot-starter.en.md",
    "content": "+++\ntitle = \"Use Spring Boot Starter\"\nweight = 2\nchapter = true\n+++\n\nElasticJob Spring Boot Starter has already integrated TracingConfiguration configuration.\nWhat developers need to do is register a bean of DataSource into the Spring IoC Container and set the type of data source.\nThen the Starter will create an instance of TracingConfiguration and register it into the container.\n\n## Import Maven Dependency\n\nImport spring-boot-starter-jdbc for DataSource register or create a bean of DataSource manually.\n\n```xml\n<dependency>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-jdbc</artifactId>\n    <version>${springboot.version}</version>\n</dependency>\n```\n\n## Configuration\n\n```yaml\nspring:\n  datasource:\n    url: jdbc:h2:mem:job_event_storage\n    driver-class-name: org.h2.Driver\n    username: sa\n    password:\n\nelasticjob:\n  tracing:\n    type: RDB\n```\n\n## Job Start\n\nTracingConfiguration will be registered into the IoC container imperceptibly after setting tracing type to RDB.\nIf elasticjob-spring-boot-starter was imported, developers need to do nothing else. \nThe instances of JobBootstrap will use the TracingConfiguration automatically.\n"
  },
  {
    "path": "docs/content/user-manual/usage/tracing/spring-namespace.cn.md",
    "content": "+++\ntitle = \"使用 Spring 命名空间\"\nweight = 3\nchapter = true\n+++\n\n## 引入 Maven 依赖\n\n引入 elasticjob-spring\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-spring-namespace</artifactId>\n    <version>${elasticjob.latest.version}</version>\n</dependency>\n```\n\n## 配置\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <!--配置作业注册中心 -->\n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"yourhost:2181\" namespace=\"my-job\" base-sleep-time-milliseconds=\"1000\" max-sleep-time-milliseconds=\"3000\" max-retries=\"3\" />\n    \n    <!-- 配置作业 Bean -->\n    <bean id=\"myJob\" class=\"xxx.MyJob\" />\n    \n    <!-- 配置数据源 -->\n    <bean id=\"tracingDataSource\" class=\"com.zaxxer.hikari.HikariDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"${driver.class.name}\" />\n        <property name=\"jdbcUrl\" value=\"${url}\" />\n        <property name=\"username\" value=\"${username}\" />\n        <property name=\"password\" value=\"${password}\" />\n    </bean>\n    <!-- 配置事件追踪 -->\n    <elasticjob:rdb-tracing id=\"elasticJobTrace\" data-source-ref=\"elasticJobTracingDataSource\" />\n    \n    <!-- 配置作业 -->\n    <elasticjob:job id=\"${myJob.id}\" job-ref=\"myJob\" registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\" sharding-total-count=\"3\" cron=\"0/1 * * * * ?\" />\n</beans>\n```\n\n## 作业启动\n\n将配置 Spring 命名空间的 xml 通过 Spring 启动，作业将自动加载。\n"
  },
  {
    "path": "docs/content/user-manual/usage/tracing/spring-namespace.en.md",
    "content": "+++\ntitle = \"Use Spring Namespace\"\nweight = 3\nchapter = true\n+++\n\n## Import Maven Dependency\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-spring-namespace</artifactId>\n    <version>${elasticjob.latest.version}</version>\n</dependency>\n```\n\n## Configuration\n\n```xml\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <!-- Configure registry center for job -->\n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"yourhost:2181\" namespace=\"my-job\" base-sleep-time-milliseconds=\"1000\" max-sleep-time-milliseconds=\"3000\" max-retries=\"3\" />\n    \n    <!-- Configure job java bean -->\n    <bean id=\"myJob\" class=\"xxx.MyJob\" />\n    \n    <!-- Configure DataSource -->\n    <bean id=\"tracingDataSource\" class=\"com.zaxxer.hikari.HikariDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"${driver.class.name}\" />\n        <property name=\"jdbcUrl\" value=\"${url}\" />\n        <property name=\"username\" value=\"${username}\" />\n        <property name=\"password\" value=\"${password}\" />\n    </bean>\n    <!-- Configure event tracing -->\n    <elasticjob:rdb-tracing id=\"elasticJobTrace\" data-source-ref=\"elasticJobTracingDataSource\" />\n    \n    <!-- Configure job -->\n    <elasticjob:job id=\"${myJob.id}\" job-ref=\"myJob\" registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\" sharding-total-count=\"3\" cron=\"0/1 * * * * ?\" />\n</beans>\n```\n\n## Job Start\n\nIf the Spring container start, the `XML` that configures the Spring namespace will be loaded, and the job will be automatically started.\n\n"
  },
  {
    "path": "docs/content/user-manual/usage/tracing/table-structure.cn.md",
    "content": "+++\ntitle = \"表结构说明\"\nweight = 4\nchapter = true\n+++\n\n事件追踪的 event_trace_rdb_url 属性对应库自动创建 JOB_EXECUTION_LOG 和 JOB_STATUS_TRACE_LOG 两张表以及若干索引。\n\n## JOB_EXECUTION_LOG 字段含义\n\n| 字段名称             | 字段类型          | 是否必填 | 描述                                           |\n|------------------|:--------------|:-----|:---------------------------------------------|\n| id               | VARCHAR(40)   | 是    | 主键                                           |\n| job_name         | VARCHAR(100)  | 是    | 作业名称                                         |\n| task_id          | VARCHAR(1000) | 是    | 任务名称,每次作业运行生成新任务                             |\n| hostname         | VARCHAR(255)  | 是    | 主机名称                                         |\n| ip               | VARCHAR(50)   | 是    | 主机IP                                         |\n| sharding_item    | INT           | 是    | 分片项                                          |\n| execution_source | VARCHAR(20)   | 是    | 作业执行来源。可选值为NORMAL_TRIGGER, MISFIRE, FAILOVER |\n| failure_cause    | VARCHAR(2000) | 否    | 执行失败原因                                       |\n| is_success       | BIT           | 是    | 是否执行成功                                       |\n| start_time       | TIMESTAMP     | 是    | 作业开始执行时间                                     |\n| complete_time    | TIMESTAMP     | 否    | 作业结束执行时间                                     |\n\nJOB_EXECUTION_LOG 记录每次作业的执行历史。\n分为两个步骤：\n\n1. 作业开始执行时向数据库插入数据，除 failure_cause 和 complete_time 外的其他字段均不为空。\n1. 作业完成执行时向数据库更新数据，更新 is_success, complete_time 和 failure_cause(如果作业执行失败)。\n\n## JOB_STATUS_TRACE_LOG 字段含义\n\n| 字段名称             | 字段类型          | 是否必填 | 描述                                                                                                    |\n|------------------|:--------------|:-----|:------------------------------------------------------------------------------------------------------|\n| id               | VARCHAR(40)   | 是    | 主键                                                                                                    |\n| job_name         | VARCHAR(100)  | 是    | 作业名称                                                                                                  |\n| original_task_id | VARCHAR(1000) | 是    | 原任务名称                                                                                                 |\n| task_id          | VARCHAR(1000) | 是    | 任务名称                                                                                                  |\n| slave_id         | VARCHAR(1000) | 是    | 执行作业服务器的 IP 地址                                                                                        |\n| execution_type   | VARCHAR(20)   | 是    | 任务执行类型，可选值为NORMAL_TRIGGER, MISFIRE, FAILOVER                                                          |\n| sharding_item    | VARCHAR(255)  | 是    | 分片项集合，多个分片项以逗号分隔                                                                                      |\n| state            | VARCHAR(20)   | 是    | 任务执行状态，可选值为TASK_STAGING, TASK_RUNNING, TASK_FINISHED, TASK_KILLED, TASK_LOST, TASK_FAILED, TASK_ERROR |\n| message          | VARCHAR(2000) | 是    | 相关信息                                                                                                  |\n| creation_time    | TIMESTAMP     | 是    | 记录创建时间                                                                                                |\n\nJOB_STATUS_TRACE_LOG 记录作业状态变更痕迹表。\n可通过每次作业运行的 task_id 查询作业状态变化的生命周期和运行轨迹。\n"
  },
  {
    "path": "docs/content/user-manual/usage/tracing/table-structure.en.md",
    "content": "+++\ntitle = \"Table Structure\"\nweight = 4\nchapter = true\n+++\n\nThe database which is the value of the event tracing property `event_trace_rdb_url` will automatically create two tables `JOB_EXECUTION_LOG` and `JOB_STATUS_TRACE_LOG` and several indexes.\n\n## JOB_EXECUTION_LOG Columns\n\n| Column name      | Column type   | Required | Describe                                                                                |\n|------------------|:--------------|:---------|:----------------------------------------------------------------------------------------|\n| id               | VARCHAR(40)   | Yes      | Primary key                                                                             |\n| job_name         | VARCHAR(100)  | Yes      | Job name                                                                                |\n| task_id          | VARCHAR(1000) | Yes      | Task name, create new tasks every time the job runs.                                    |\n| hostname         | VARCHAR(255)  | Yes      | Hostname                                                                                |\n| ip               | VARCHAR(50)   | Yes      | IP                                                                                      |\n| sharding_item    | INT           | Yes      | Sharding item                                                                           |\n| execution_source | VARCHAR(20)   | Yes      | Source of job execution. The value options are `NORMAL_TRIGGER`, `MISFIRE`, `FAILOVER`. |\n| failure_cause    | VARCHAR(2000) | No       | The reason for execution failure                                                        |\n| is_success       | BIT           | Yes      | Execute successfully or not                                                             |\n| start_time       | TIMESTAMP     | Yes      | Job start time                                                                          |\n| complete_time    | TIMESTAMP     | No       | Job end time                                                                            |\n\n`JOB_EXECUTION_LOG` records the execution history of each job.\nThere are two steps:\n\n1. When the job is executed, program will create one record in the `JOB_EXECUTION_LOG`, and all fields except `failure_cause` and `complete_time` are not empty.\n1. When the job completes execution, program will update the record, update the columns of `is_success`, `complete_time` and `failure_cause`(if the job execution fails).\n\n## JOB_STATUS_TRACE_LOG Columns\n\n| Column name      | Column type   | Required | Describe                                                                                                                                                |\n|------------------|:--------------|:---------|:--------------------------------------------------------------------------------------------------------------------------------------------------------|\n| id               | VARCHAR(40)   | Yes      | Primary key                                                                                                                                             |\n| job_name         | VARCHAR(100)  | Yes      | Job name                                                                                                                                                |\n| original_task_id | VARCHAR(1000) | Yes      | Original task name                                                                                                                                      |\n| task_id          | VARCHAR(1000) | Yes      | Task name                                                                                                                                               |\n| slave_id         | VARCHAR(1000) | Yes      | Server's name of executing the job. The valve is server's IP.                                                                                           |\n| execution_type   | VARCHAR(20)   | Yes      | Type of job execution, the value options are `NORMAL_TRIGGER`, `MISFIRE`, `FAILOVER`.                                                                   |\n| sharding_item    | VARCHAR(255)  | Yes      | Collection of sharding item, multiple sharding items are separated by commas.                                                                           |\n| state            | VARCHAR(20)   | Yes      | State of job execution, the value options are `TASK_STAGING`, `TASK_RUNNING`, `TASK_FINISHED`, `TASK_KILLED`, `TASK_LOST`, `TASK_FAILED`, `TASK_ERROR`. |\n| message          | VARCHAR(2000) | Yes      | Message                                                                                                                                                 |\n| creation_time    | TIMESTAMP     | Yes      | Create time                                                                                                                                             |\n\n`JOB_STATUS_TRACE_LOG` record the job status changes.\nThrough the `task_id` of each job, user can query the life cycle and running track of the job status change.\n"
  },
  {
    "path": "docs/i18n/cn.toml",
    "content": "[Search-placeholder]\nother = \"Search...\"\n\n[Clear-History]\nother = \"Clear History\"\n\n[Attachments-label]\nother = \"Attachments\"\n\n[title-404]\nother = \"Error\"\n\n[message-404]\nother = \"Woops. Looks like this page doesn't exist ¯\\\\_(ツ)_/¯.\"\n\n[Go-to-homepage]\nother = \"Go to homepage\"\n\n[Edit-this-page]\nother = \"Edit this page\"\n\n[Shortcuts-Title]\nother = \"More\"\n\n[Expand-title]\nother = \"Expand me...\""
  },
  {
    "path": "docs/layouts/index.html",
    "content": "<!DOCTYPE html>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"refresh\" content=\"0; url=https://shardingsphere.apache.org/elasticjob/current/en/overview/\">\n    <title>Index</title>\n</head>\n<body>\n</body>\n</html>\n"
  },
  {
    "path": "docs/layouts/partials/favicon.html",
    "content": "<link rel=\"shortcut icon\" href=\"https://shardingsphere.apache.org/elasticjob/images/favicon.png\" type=\"image/x-icon\" />\n"
  },
  {
    "path": "docs/layouts/partials/javascript.html",
    "content": "<script src=\"http://cdn.bootcss.com/highlight.js/9.8.0/highlight.min.js\"></script>\n<script>hljs.initHighlightingOnLoad();</script>\n"
  },
  {
    "path": "docs/layouts/partials/logo.html",
    "content": "<!--\n * @Author: your name\n * @Date: 2022-04-14 15:05:07\n * @LastEditTime: 2022-04-14 16:32:03\n * @LastEditors: Please set LastEditors\n * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\n * @FilePath: /discourse/Users/david/Documents/expmle/shardingsphere-elasticjob/docs/layouts/partials/logo.html\n-->\n<!-- <img src=\"https://shardingsphere.apache.org/elasticjob/current/img/elasticjob.png\" /> -->\n<img src=\"https://shardingsphere.apache.org/elasticjob/current/img/elasticjob-orange.png\" />\n\n"
  },
  {
    "path": "docs/layouts/partials/menu-footer.html",
    "content": "<p></p>\n"
  },
  {
    "path": "docs/layouts/partials/style.html",
    "content": "<link rel=\"stylesheet\" href=\"http://cdn.bootcss.com/highlight.js/9.8.0/styles/monokai-sublime.min.css\">\n<link rel=\"stylesheet\" href=\"https://shardingsphere.apache.org/elasticjob/current/lite/css/style.css\">"
  },
  {
    "path": "docs/layouts/partials/toc.html",
    "content": "{{ if and (gt .WordCount 400 ) (.Params.toc) }}\n<aside>\n    <header>\n    <h2>{{.Title}}</h2>\n    </header>\n    {{.TableOfContents}}\n</aside>\n{{ end }}"
  },
  {
    "path": "docs/layouts/shortcodes/bilibili.html",
    "content": "<!DOCTYPE HTML>\n<html>\n\n<head>\n    <style type=\"text/css\">\n        .aspect-ratio {\n            position: relative;\n            width: 100%;\n            height: 0;\n            padding-bottom: 75%;\n        }\n\n        .aspect-ratio iframe {\n            position: absolute;\n            width: 100%;\n            height: 100%;\n            left: 0;\n            top: 0;\n        }\n    </style>\n</head>\n\n<body>\n    <div class=\"aspect-ratio\">\n        <iframe\n            src=\"https://player.bilibili.com/player.html?bvid={{.Get 0 }}&page={{ if .Get 1 }}{{.Get 1}}{{ else }}1&high_quality=1&danmaku=0{{end}}\"\n            scrolling=\"no\" \n            border=\"0\" \n            frameborder=\"no\" \n            framespacing=\"0\" \n            allowfullscreen=\"true\"\n            sandbox=\"allow-top-navigation allow-same-origin allow-forms allow-scripts\"\n            >\n        </iframe>\n    </div>\n</body>\n\n</html>\n\n<!-- arguements &high_quality=1&danmaku=0 in src control the quality of video and bullet-screen comments-->\n<!-- sandbox option avoid jumpping to bilibili.com -->"
  },
  {
    "path": "docs/static/css/style.css",
    "content": "/* background behind the logo*/\n#header {\n    background: black;\n    border-color: black;\n}\n\n#header-wrapper {\n    background: black;\n    border-color: black;\n}\n\n#chapter p {\n    text-align: left;\n}\n\n.copy-to-clipboard {\n    background-image: none;\n    display: none;\n}\n\n#body img, #body .video-container {\n    margin: auto;\n    text-align: left;\n    display: inherit;\n}\n "
  },
  {
    "path": "docs/static/css/theme-black.css",
    "content": "@charset \"UTF-8\";\n\n#top-github-link,\n#body #breadcrumbs {\n    position: relative;\n    top: 50%;\n    -webkit-transform: translateY(-50%);\n    -moz-transform: translateY(-50%);\n    -o-transform: translateY(-50%);\n    -ms-transform: translateY(-50%);\n    transform: translateY(-50%);\n}\n\n.button,\n.button-secondary {\n    display: inline-block;\n    padding: 7px 12px;\n}\n\n.button:active,\n.button-secondary:active {\n    margin: 2px 0 -2px 0;\n}\n\n@font-face {\n    font-family: 'Novacento Sans Wide';\n    src: url(\"../fonts/Novecentosanswide-UltraLight-webfont.eot\");\n    src: url(\"../fonts/Novecentosanswide-UltraLight-webfont.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/Novecentosanswide-UltraLight-webfont.woff2\") format(\"woff2\"), url(\"../fonts/Novecentosanswide-UltraLight-webfont.woff\") format(\"woff\"), url(\"../fonts/Novecentosanswide-UltraLight-webfont.ttf\") format(\"truetype\"), url(\"../fonts/Novecentosanswide-UltraLight-webfont.svg#novecento_sans_wideultralight\") format(\"svg\");\n    font-style: normal;\n    font-weight: 200;\n}\n\n@font-face {\n    font-family: 'Work Sans';\n    font-style: normal;\n    font-weight: 300;\n    src: url(\"../fonts/Work_Sans_300.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/Work_Sans_300.woff\") format(\"woff\"), url(\"../fonts/Work_Sans_300.woff2\") format(\"woff2\"), url(\"../fonts/Work_Sans_300.svg#WorkSans\") format(\"svg\"), url(\"../fonts/Work_Sans_300.ttf\") format(\"truetype\");\n}\n\n@font-face {\n    font-family: 'Work Sans';\n    font-style: normal;\n    font-weight: 500;\n    src: url(\"../fonts/Work_Sans_500.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/Work_Sans_500.woff\") format(\"woff\"), url(\"../fonts/Work_Sans_500.woff2\") format(\"woff2\"), url(\"../fonts/Work_Sans_500.svg#WorkSans\") format(\"svg\"), url(\"../fonts/Work_Sans_500.ttf\") format(\"truetype\");\n}\n\nbody {\n    background: #fff;\n    color: #777;\n}\n\nbody #chapter h1 {\n    font-size: 3.5rem;\n}\n\n@media only all and (min-width: 48em) and (max-width: 59.938em) {\n    body #chapter h1 {\n        font-size: 3rem;\n    }\n}\n\n@media only all and (max-width: 47.938em) {\n    body #chapter h1 {\n        font-size: 2rem;\n    }\n}\n\na {\n    /* color: #00bdf3; */\n    color: rgba(15, 88, 163, 1);\n}\n\na:hover {\n    /* color: #0082a7; */\n    color: #0a4f90;\n}\n\npre {\n    position: relative;\n    color: #ffffff;\n}\n\n.bg {\n    background: #fff;\n    border: 1px solid #eaeaea;\n}\n\nb,\nstrong,\nlabel,\nth {\n    font-weight: 600;\n}\n\n.default-animation,\n#header #logo-svg,\n#header #logo-svg path,\n#sidebar,\n#sidebar ul,\n#body,\n#body .padding,\n#body .nav {\n    -webkit-transition: backgroud-color 0.2s ease;\n    -moz-transition: backgroud-color 0.2s ease;\n    transition: backgroud-color 0.2s ease;\n}\n\n#grav-logo {\n    max-width: 60%;\n}\n\n#grav-logo path {\n    fill: #fff !important;\n}\n\n#sidebar {\n    font-weight: 300 !important;\n}\n\nfieldset {\n    border: 1px solid #ddd;\n}\n\ntextarea,\ninput[type=\"email\"],\ninput[type=\"number\"],\ninput[type=\"password\"],\ninput[type=\"search\"],\ninput[type=\"tel\"],\ninput[type=\"text\"],\ninput[type=\"url\"],\ninput[type=\"color\"],\ninput[type=\"date\"],\ninput[type=\"datetime\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"],\ninput[type=\"time\"],\ninput[type=\"week\"],\nselect[multiple=multiple] {\n    background-color: white;\n    border: 1px solid #ddd;\n    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06);\n}\n\ntextarea:hover,\ninput[type=\"email\"]:hover,\ninput[type=\"number\"]:hover,\ninput[type=\"password\"]:hover,\ninput[type=\"search\"]:hover,\ninput[type=\"tel\"]:hover,\ninput[type=\"text\"]:hover,\ninput[type=\"url\"]:hover,\ninput[type=\"color\"]:hover,\ninput[type=\"date\"]:hover,\ninput[type=\"datetime\"]:hover,\ninput[type=\"datetime-local\"]:hover,\ninput[type=\"month\"]:hover,\ninput[type=\"time\"]:hover,\ninput[type=\"week\"]:hover,\nselect[multiple=multiple]:hover {\n    border-color: #c4c4c4;\n}\n\ntextarea:focus,\ninput[type=\"email\"]:focus,\ninput[type=\"number\"]:focus,\ninput[type=\"password\"]:focus,\ninput[type=\"search\"]:focus,\ninput[type=\"tel\"]:focus,\ninput[type=\"text\"]:focus,\ninput[type=\"url\"]:focus,\ninput[type=\"color\"]:focus,\ninput[type=\"date\"]:focus,\ninput[type=\"datetime\"]:focus,\ninput[type=\"datetime-local\"]:focus,\ninput[type=\"month\"]:focus,\ninput[type=\"time\"]:focus,\ninput[type=\"week\"]:focus,\nselect[multiple=multiple]:focus {\n    border-color: #00bdf3;\n    box-shadow: inset 0 1px 3px rgba(0, 0, 0, .06), 0 0 5px rgba(0, 169, 218, .7)\n}\n\n#header-wrapper {\n    background: black;\n    border-color: black;\n    text-align: center;\n    border-bottom: 4px solid black;\n    padding: 1rem;\n}\n\n#header a {\n    display: inline-block;\n}\n\n#header #logo-svg {\n    width: 8rem;\n    height: 2rem;\n}\n\n#header #logo-svg path {\n    fill: #fff;\n}\n\n.searchbox {\n    margin-top: 1rem;\n    position: relative;\n    border: 1px solid #322A38;\n    background: #322A38;\n    border-radius: 4px;\n}\n\n.searchbox label {\n    color: rgba(255, 255, 255, 0.8);\n    position: absolute;\n    left: 10px;\n    top: 3px;\n}\n\n.searchbox span {\n    color: rgba(255, 255, 255, 0.6);\n    position: absolute;\n    right: 10px;\n    top: 3px;\n    cursor: pointer;\n}\n\n.searchbox span:hover {\n    color: rgba(255, 255, 255, 0.9);\n}\n\n.searchbox input {\n    display: inline-block;\n    color: #fff;\n    width: 100%;\n    height: 30px;\n    background: transparent;\n    border: 0;\n    padding: 0 25px 0 30px;\n    margin: 0;\n    font-weight: 300;\n}\n\n.searchbox input::-webkit-input-placeholder {\n    color: rgba(255, 255, 255, 0.6);\n}\n\n.searchbox input::-moz-placeholder {\n    color: rgba(255, 255, 255, 0.6);\n}\n\n.searchbox input:-moz-placeholder {\n    color: rgba(255, 255, 255, 0.6);\n}\n\n.searchbox input:-ms-input-placeholder {\n    color: rgba(255, 255, 255, 0.6);\n}\n\n#sidebar-toggle-span {\n    display: none;\n}\n\n@media only all and (max-width: 47.938em) {\n    #sidebar-toggle-span {\n        display: inline;\n    }\n}\n\n#sidebar {\n    /* background-color: #322A38; */\n    background-color: rgba(2, 30, 62, 0.95);\n    position: fixed;\n    top: 0;\n    width: 300px;\n    bottom: 0;\n    left: 0;\n    font-weight: 400;\n    font-size: 15px;\n}\n\n#sidebar a {\n    color: #ccc;\n}\n\n#sidebar a:hover {\n    color: #e6e6e6;\n}\n\n#sidebar a.subtitle {\n    color: rgba(204, 204, 204, 0.6);\n}\n\n#sidebar hr {\n    border-bottom: 1px solid #2a232f;\n}\n\n#sidebar a.padding {\n    padding: 0 1rem;\n}\n\n#sidebar h5 {\n    margin: 2rem 0 0;\n    position: relative;\n    line-height: 2;\n}\n\n#sidebar h5 a {\n    display: block;\n    margin-left: 0;\n    margin-right: 0;\n    padding-left: 1rem;\n    padding-right: 1rem;\n}\n\n#sidebar h5 i {\n    color: rgba(204, 204, 204, 0.6);\n    position: absolute;\n    right: 0.6rem;\n    top: 0.7rem;\n    font-size: 80%;\n}\n\n#sidebar h5.parent a {\n    background: #201b24;\n    color: #d9d9d9 !important;\n}\n\n#sidebar h5.active a {\n    background: #fff;\n    color: #777 !important;\n}\n\n#sidebar h5.active i {\n    color: #777 !important;\n}\n\n#sidebar h5+ul.topics {\n    display: none;\n    margin-top: 0;\n}\n\n#sidebar h5.parent+ul.topics,\n#sidebar h5.active+ul.topics {\n    display: block;\n}\n\n#sidebar ul {\n    list-style: none;\n    padding: 0;\n    margin: 0;\n}\n\n#sidebar ul.searched a {\n    color: #999999;\n}\n\n#sidebar ul.searched .search-match a {\n    color: #e6e6e6;\n}\n\n#sidebar ul.searched .search-match a:hover {\n    color: white;\n}\n\n#sidebar ul.topics {\n    margin: 0 1rem;\n}\n\n#sidebar ul.topics.searched ul {\n    display: block;\n}\n\n#sidebar ul.topics ul {\n    display: none;\n    padding-bottom: 1rem;\n}\n\n#sidebar ul.topics ul ul {\n    padding-bottom: 0;\n}\n\n#sidebar ul.topics li.parent>ul,\n#sidebar ul.topics>li.active>ul {\n    display: block;\n}\n\n#sidebar ul.topics>li>a {\n    line-height: 2rem;\n    font-size: 1.1rem;\n}\n\n#sidebar ul.topics>li>a b {\n    opacity: 0.5;\n    font-weight: normal;\n}\n\n#sidebar ul.topics>li>a .fa {\n    margin-top: 9px;\n}\n\n#sidebar ul.topics>li.parent,\n#sidebar ul.topics>li.active {\n    /* background: #251f29; */\n    background: rgba(88, 100, 120, 0.41);\n    margin-left: -1rem;\n    margin-right: -1rem;\n    padding-left: 1rem;\n    padding-right: 1rem;\n}\n\n#sidebar ul li.active>a {\n    background: #fff;\n    color: #777 !important;\n    margin-left: -1rem;\n    margin-right: -1rem;\n    padding-left: 1rem;\n    padding-right: 1rem;\n}\n\n#sidebar ul li {\n    padding: 0;\n}\n\n#sidebar ul li.visited+span {\n    margin-right: 16px;\n}\n\n#sidebar ul li a {\n    display: block;\n    padding: 2px 0;\n}\n\n#sidebar ul li a span {\n    text-overflow: ellipsis;\n    overflow: hidden;\n    white-space: nowrap;\n    display: block;\n}\n\n#sidebar ul li>a {\n    padding: 4px 0;\n}\n\n#sidebar ul li.visited>a .read-icon {\n    color: #9c6fb6;\n    display: inline;\n}\n\n#sidebar ul li li {\n    padding-left: 1rem;\n    text-indent: 0.2rem;\n}\n\n#main {\n    background: #f7f7f7;\n    margin: 0 0 1.563rem 0;\n}\n\n#body {\n    position: relative;\n    margin-left: 300px;\n    min-height: 100%;\n}\n\n#body img,\n#body .video-container {\n    margin: auto;\n    text-align: left;\n    display: inherit;\n    max-width: 100%;\n    /* set img size */\n}\n\n#body img.border,\n#body .video-container.border {\n    border: 2px solid #e6e6e6 !important;\n    padding: 2px;\n}\n\n#body img.shadow,\n#body .video-container.shadow {\n    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);\n}\n\n#body img.inline {\n    display: inline !important;\n    margin: 0 !important;\n    vertical-align: bottom;\n}\n\n#body .bordered {\n    border: 1px solid #ccc;\n}\n\n#body .padding {\n    padding: 3rem 6rem;\n}\n\n@media only all and (max-width: 59.938em) {\n    #body .padding {\n        position: static;\n        padding: 15px 3rem;\n    }\n}\n\n@media only all and (max-width: 47.938em) {\n    #body .padding {\n        padding: 5px 1rem;\n    }\n}\n\n#body h1+hr {\n    margin-top: -1.7rem;\n    margin-bottom: 3rem;\n}\n\n@media only all and (max-width: 59.938em) {\n    #body #navigation {\n        position: static;\n        margin-right: 0 !important;\n        width: 100%;\n        display: table;\n    }\n}\n\n#body .nav {\n    position: fixed;\n    top: 0;\n    bottom: 0;\n    width: 4rem;\n    font-size: 50px;\n    height: 100%;\n    cursor: pointer;\n    display: table;\n    text-align: center;\n}\n\n#body .nav>i {\n    display: table-cell;\n    vertical-align: middle;\n    text-align: center;\n}\n\n@media only all and (max-width: 59.938em) {\n    #body .nav {\n        display: table-cell;\n        position: static;\n        top: auto;\n        width: 50%;\n        text-align: center;\n        height: 100px;\n        line-height: 100px;\n        padding-top: 0;\n    }\n\n    #body .nav>i {\n        display: inline-block;\n    }\n}\n\n#body .nav:hover {\n    background: #F6F6F6;\n}\n\n#body .nav.nav-pref {\n    left: 0;\n}\n\n#body .nav.nav-next {\n    right: 0;\n}\n\n#body-inner {\n    margin-bottom: 5rem;\n}\n\n#chapter {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    height: 100%;\n    padding: 2rem 0;\n}\n\n#chapter #body-inner {\n    padding-bottom: 3rem;\n    max-width: 90%;\n}\n\n#chapter h3 {\n    font-family: \"Work Sans\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    font-weight: 300;\n    text-align: center;\n}\n\n#chapter h1 {\n    font-size: 5rem;\n    border-bottom: 4px solid #F0F2F4;\n}\n\n#chapter p {\n    text-align: left;\n}\n\n#footer {\n    padding: 3rem 1rem;\n    color: #b3b3b3;\n    font-size: 13px;\n}\n\n#footer p {\n    margin: 0;\n}\n\nbody {\n    font-family: \"Work Sans\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    font-weight: 300;\n    line-height: 1.6;\n    /* font-size: 18px !important; */\n    font-size: 16px !important;\n}\n\nh2,\nh3,\nh4,\nh5,\nh6 {\n    font-family: \"Work Sans\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    text-rendering: optimizeLegibility;\n    color: #5e5e5e;\n    font-weight: 400;\n    letter-spacing: -1px;\n}\n\nh1 {\n    font-family: \"Novacento Sans Wide\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    text-align: center;\n    text-transform: uppercase;\n    color: #222;\n    font-weight: 200;\n}\n\nblockquote {\n    border-left: 10px solid #F0F2F4;\n}\n\nblockquote p {\n    font-size: 1.1rem;\n    color: #999;\n}\n\nblockquote cite {\n    display: block;\n    text-align: right;\n    color: #666;\n    font-size: 1.2rem;\n}\n\ndiv.notices {\n    margin: 2rem 0;\n    position: relative;\n}\n\ndiv.notices p {\n    padding: 15px;\n    display: block;\n    font-size: 1rem;\n    margin-top: 0rem;\n    margin-bottom: 0rem;\n    color: #666;\n}\n\ndiv.notices p:first-child:before {\n    position: absolute;\n    top: 2px;\n    color: #fff;\n    font-family: FontAwesome;\n    content: '';\n    left: 10px;\n}\n\ndiv.notices p:first-child:after {\n    position: absolute;\n    top: 2px;\n    color: #fff;\n    left: 2rem;\n}\n\ndiv.notices.info p {\n    border-top: 30px solid #F0B37E;\n    background: #FFF2DB;\n}\n\ndiv.notices.info p:first-child:after {\n    content: 'Info';\n}\n\ndiv.notices.warning p {\n    border-top: 30px solid rgba(217, 83, 79, 0.8);\n    background: #FAE2E2;\n}\n\ndiv.notices.warning p:first-child:after {\n    content: 'Warning';\n}\n\ndiv.notices.note p {\n    border-top: 30px solid #6AB0DE;\n    background: #E7F2FA;\n}\n\ndiv.notices.note p:first-child:after {\n    content: 'Note';\n}\n\ndiv.notices.tip p {\n    border-top: 30px solid rgba(92, 184, 92, 0.8);\n    background: #E6F9E6;\n}\n\ndiv.notices.tip p:first-child:after {\n    content: 'Tip';\n}\n\n/* attachments shortcode */\n\nsection.attachments {\n    margin: 2rem 0;\n    position: relative;\n}\n\nsection.attachments label {\n    font-weight: 400;\n    padding-left: 0.5em;\n    padding-top: 0.2em;\n    padding-bottom: 0.2em;\n    margin: 0;\n}\n\nsection.attachments .attachments-files {\n    padding: 15px;\n    display: block;\n    font-size: 1rem;\n    margin-top: 0rem;\n    margin-bottom: 0rem;\n    color: #666;\n}\n\nsection.attachments.orange label {\n    color: #fff;\n    background: #F0B37E;\n}\n\nsection.attachments.orange .attachments-files {\n    background: #FFF2DB;\n}\n\nsection.attachments.green label {\n    color: #fff;\n    background: rgba(92, 184, 92, 0.8);\n}\n\nsection.attachments.green .attachments-files {\n    background: #E6F9E6;\n}\n\nsection.attachments.blue label {\n    color: #fff;\n    background: #6AB0DE;\n}\n\nsection.attachments.blue .attachments-files {\n    background: #E7F2FA;\n}\n\nsection.attachments.grey label {\n    color: #fff;\n    background: #505d65;\n}\n\nsection.attachments.grey .attachments-files {\n    background: #f4f4f4;\n}\n\n/* Children shortcode */\n\n/* Children shortcode */\n.children p {\n    font-size: small;\n    margin-top: 0px;\n    padding-top: 0px;\n    margin-bottom: 0px;\n    padding-bottom: 0px;\n}\n\n.children-li p {\n    font-size: small;\n    font-style: italic;\n\n}\n\n.children-h2 p,\n.children-h3 p {\n    font-size: small;\n    margin-top: 0px;\n    padding-top: 0px;\n    margin-bottom: 0px;\n    padding-bottom: 0px;\n}\n\n.children h3,\n.children h2 {\n    margin-bottom: 0px;\n    margin-top: 5px;\n}\n\ncode,\nkbd,\npre,\nsamp {\n    font-family: \"Consolas\", menlo, monospace;\n    font-size: 92%;\n}\n\ncode {\n    border-radius: 2px;\n    white-space: nowrap;\n    color: #5e5e5e;\n    /* background: #FFF7DD; */\n    background: rgba(40, 130, 209, 0.23);\n    border-radius: 0.5rem;\n    /* border: 1px solid #fbf0cb; */\n    /* padding: 0px 2px; */\n    padding: 0px 5px;\n}\n\ncode+.copy-to-clipboard {\n    margin-left: -1px;\n    border-left: 0 !important;\n    font-size: inherit !important;\n    vertical-align: middle;\n    height: 21px;\n    top: 0;\n}\n\npre {\n    padding: 1rem;\n    margin: 2rem 0;\n    background: #1d1f21;\n    border: 0;\n    border-radius: 2px;\n    line-height: 1.15;\n}\n\npre code {\n    color: whitesmoke;\n    background: inherit;\n    white-space: inherit;\n    border: 0;\n    padding: 0;\n    margin: 0;\n    font-size: 15px;\n}\n\nhr {\n    border-bottom: 4px solid #F0F2F4;\n}\n\n.page-title {\n    margin-top: -25px;\n    padding: 25px;\n    float: left;\n    clear: both;\n    background: #9c6fb6;\n    color: #fff;\n}\n\n#body a.anchor-link {\n    color: #ccc;\n}\n\n#body a.anchor-link:hover {\n    color: #9c6fb6;\n}\n\n#body-inner .tabs-wrapper.ui-theme-badges {\n    background: #1d1f21;\n}\n\n#body-inner .tabs-wrapper.ui-theme-badges .tabs-nav li {\n    font-size: 0.9rem;\n    text-transform: uppercase;\n}\n\n#body-inner .tabs-wrapper.ui-theme-badges .tabs-nav li a {\n    background: #35393c;\n}\n\n#body-inner .tabs-wrapper.ui-theme-badges .tabs-nav li.current a {\n    background: #4d5257;\n}\n\n#body-inner pre {\n    white-space: pre-wrap;\n}\n\n.tabs-wrapper pre {\n    margin: 1rem 0;\n    border: 0;\n    padding: 0;\n    background: inherit;\n}\n\ntable {\n    border: 1px solid #eaeaea;\n    table-layout: auto;\n}\n\nth {\n    background: #f7f7f7;\n    padding: 0.5rem;\n}\n\ntd {\n    padding: 0.5rem;\n    border: 1px solid #eaeaea;\n}\n\n.button {\n    background: #9c6fb6;\n    color: #fff;\n    box-shadow: 0 3px 0 #00a5d4;\n}\n\n.button:hover {\n    background: #00a5d4;\n    box-shadow: 0 3px 0 #008db6;\n    color: #fff;\n}\n\n.button:active {\n    box-shadow: 0 1px 0 #008db6;\n}\n\n.button-secondary {\n    background: #F8B450;\n    color: #fff;\n    box-shadow: 0 3px 0 #f7a733;\n}\n\n.button-secondary:hover {\n    background: #f7a733;\n    box-shadow: 0 3px 0 #f69b15;\n    color: #fff;\n}\n\n.button-secondary:active {\n    box-shadow: 0 1px 0 #f69b15;\n}\n\n.bullets {\n    margin: 1.7rem 0;\n    margin-left: -0.85rem;\n    margin-right: -0.85rem;\n    overflow: auto;\n}\n\n.bullet {\n    float: left;\n    padding: 0 0.85rem;\n}\n\n.two-column-bullet {\n    width: 50%;\n}\n\n@media only all and (max-width: 47.938em) {\n    .two-column-bullet {\n        width: 100%;\n    }\n}\n\n.three-column-bullet {\n    width: 33.33333%;\n}\n\n@media only all and (max-width: 47.938em) {\n    .three-column-bullet {\n        width: 100%;\n    }\n}\n\n.four-column-bullet {\n    width: 25%;\n}\n\n@media only all and (max-width: 47.938em) {\n    .four-column-bullet {\n        width: 100%;\n    }\n}\n\n.bullet-icon {\n    float: left;\n    background: #9c6fb6;\n    padding: 0.875rem;\n    width: 3.5rem;\n    height: 3.5rem;\n    border-radius: 50%;\n    color: #fff;\n    font-size: 1.75rem;\n    text-align: center;\n}\n\n.bullet-icon-1 {\n    background: #9c6fb6;\n}\n\n.bullet-icon-2 {\n    background: #00f3d8;\n}\n\n.bullet-icon-3 {\n    background: #e6f300;\n}\n\n.bullet-content {\n    margin-left: 4.55rem;\n}\n\n.tooltipped {\n    position: relative;\n}\n\n.tooltipped:after {\n    position: absolute;\n    z-index: 1000000;\n    display: none;\n    padding: 5px 8px;\n    font: normal normal 11px/1.5 \"Work Sans\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    color: #fff;\n    text-align: center;\n    text-decoration: none;\n    text-shadow: none;\n    text-transform: none;\n    letter-spacing: normal;\n    word-wrap: break-word;\n    white-space: pre;\n    pointer-events: none;\n    content: attr(aria-label);\n    background: rgba(0, 0, 0, 0.8);\n    border-radius: 3px;\n    -webkit-font-smoothing: subpixel-antialiased;\n}\n\n.tooltipped:before {\n    position: absolute;\n    z-index: 1000001;\n    display: none;\n    width: 0;\n    height: 0;\n    color: rgba(0, 0, 0, 0.8);\n    pointer-events: none;\n    content: \"\";\n    border: 5px solid transparent;\n}\n\n.tooltipped:hover:before,\n.tooltipped:hover:after,\n.tooltipped:active:before,\n.tooltipped:active:after,\n.tooltipped:focus:before,\n.tooltipped:focus:after {\n    display: inline-block;\n    text-decoration: none;\n}\n\n.tooltipped-s:after,\n.tooltipped-se:after,\n.tooltipped-sw:after {\n    top: 100%;\n    right: 50%;\n    margin-top: 5px;\n}\n\n.tooltipped-s:before,\n.tooltipped-se:before,\n.tooltipped-sw:before {\n    top: auto;\n    right: 50%;\n    bottom: -5px;\n    margin-right: -5px;\n    border-bottom-color: rgba(0, 0, 0, 0.8);\n}\n\n.tooltipped-se:after {\n    right: auto;\n    left: 50%;\n    margin-left: -15px;\n}\n\n.tooltipped-sw:after {\n    margin-right: -15px;\n}\n\n.tooltipped-n:after,\n.tooltipped-ne:after,\n.tooltipped-nw:after {\n    right: 50%;\n    bottom: 100%;\n    margin-bottom: 5px;\n}\n\n.tooltipped-n:before,\n.tooltipped-ne:before,\n.tooltipped-nw:before {\n    top: -5px;\n    right: 50%;\n    bottom: auto;\n    margin-right: -5px;\n    border-top-color: rgba(0, 0, 0, 0.8);\n}\n\n.tooltipped-ne:after {\n    right: auto;\n    left: 50%;\n    margin-left: -15px;\n}\n\n.tooltipped-nw:after {\n    margin-right: -15px;\n}\n\n.tooltipped-s:after,\n.tooltipped-n:after {\n    transform: translateX(50%);\n}\n\n.tooltipped-w:after {\n    right: 100%;\n    bottom: 50%;\n    margin-right: 5px;\n    transform: translateY(50%);\n}\n\n.tooltipped-w:before {\n    top: 50%;\n    bottom: 50%;\n    left: -5px;\n    margin-top: -5px;\n    border-left-color: rgba(0, 0, 0, 0.8);\n}\n\n.tooltipped-e:after {\n    bottom: 50%;\n    left: 100%;\n    margin-left: 5px;\n    transform: translateY(50%);\n}\n\n.tooltipped-e:before {\n    top: 50%;\n    right: -5px;\n    bottom: 50%;\n    margin-top: -5px;\n    border-right-color: rgba(0, 0, 0, 0.8);\n}\n\n.highlightable {\n    padding: 1rem 0 1rem;\n    overflow: auto;\n    position: relative;\n}\n\n.hljs::selection,\n.hljs span::selection {\n    background: #b7b7b7;\n}\n\n.lightbox-active #body {\n    overflow: visible;\n}\n\n.lightbox-active #body .padding {\n    overflow: visible;\n}\n\n#github-contrib i {\n    vertical-align: middle;\n}\n\n.featherlight img {\n    margin: 0 !important;\n}\n\n.lifecycle #body-inner ul {\n    list-style: none;\n    margin: 0;\n    padding: 2rem 0 0;\n    position: relative;\n}\n\n.lifecycle #body-inner ol {\n    margin: 1rem 0 1rem 0;\n    padding: 2rem;\n    position: relative;\n}\n\n.lifecycle #body-inner ol li {\n    margin-left: 1rem;\n}\n\n.lifecycle #body-inner ol strong,\n.lifecycle #body-inner ol label,\n.lifecycle #body-inner ol th {\n    text-decoration: underline;\n}\n\n.lifecycle #body-inner ol ol {\n    margin-left: -1rem;\n}\n\n.lifecycle #body-inner h3[class*='level'] {\n    font-size: 20px;\n    position: absolute;\n    margin: 0;\n    padding: 4px 10px;\n    right: 0;\n    z-index: 1000;\n    color: #fff;\n    background: #1ABC9C;\n}\n\n.lifecycle #body-inner ol h3 {\n    margin-top: 1rem !important;\n    right: 2rem !important;\n}\n\n.lifecycle #body-inner .level-1+ol {\n    background: #f6fefc;\n    border: 4px solid #1ABC9C;\n    color: #16A085;\n}\n\n.lifecycle #body-inner .level-1+ol h3 {\n    background: #2ECC71;\n}\n\n.lifecycle #body-inner .level-2+ol {\n    background: #f7fdf9;\n    border: 4px solid #2ECC71;\n    color: #27AE60;\n}\n\n.lifecycle #body-inner .level-2+ol h3 {\n    background: #3498DB;\n}\n\n.lifecycle #body-inner .level-3+ol {\n    background: #f3f9fd;\n    border: 4px solid #3498DB;\n    color: #2980B9;\n}\n\n.lifecycle #body-inner .level-3+ol h3 {\n    background: #34495E;\n}\n\n.lifecycle #body-inner .level-4+ol {\n    background: #e4eaf0;\n    border: 4px solid #34495E;\n    color: #2C3E50;\n}\n\n.lifecycle #body-inner .level-4+ol h3 {\n    background: #34495E;\n}\n\n#top-bar {\n    /* background: #F6F6F6; */\n    background: rgba(195, 211, 229, 0.82);\n    /* border-radius: 2px; */\n    border-radius: 4px;\n    padding: 0 1rem;\n    height: 0;\n    min-height: 3rem;\n}\n\n#top-github-link {\n    position: relative;\n    z-index: 1;\n    float: right;\n    display: block;\n}\n\n#body #breadcrumbs {\n    height: auto;\n    margin-bottom: 0;\n    padding-left: 0;\n    line-height: 1.4;\n    overflow: hidden;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n    width: 70%;\n    display: inline-block;\n    float: left;\n}\n\n#body #breadcrumbs span {\n    padding: 0 0.1rem;\n}\n\n@media only all and (max-width: 59.938em) {\n    #sidebar {\n        width: 230px;\n    }\n\n    #body {\n        margin-left: 230px;\n    }\n}\n\n@media only all and (max-width: 47.938em) {\n    #sidebar {\n        width: 230px;\n        left: -230px;\n    }\n\n    #body {\n        margin-left: 0;\n        width: 100%;\n    }\n\n    .sidebar-hidden {\n        overflow: hidden;\n    }\n\n    .sidebar-hidden #sidebar {\n        left: 0;\n    }\n\n    .sidebar-hidden #body {\n        margin-left: 230px;\n        overflow: hidden;\n    }\n\n    .sidebar-hidden #overlay {\n        position: absolute;\n        left: 0;\n        right: 0;\n        top: 0;\n        bottom: 0;\n        z-index: 10;\n        background: rgba(255, 255, 255, 0.5);\n        cursor: pointer;\n    }\n}\n\n.copy-to-clipboard {\n    background-image: none;\n    background-position: 50% 50%;\n    background-size: 16px 16px;\n    background-repeat: no-repeat;\n    width: 27px;\n    height: 1.45rem;\n    top: -1px;\n    display: none;\n    vertical-align: middle;\n    position: relative;\n    color: #5e5e5e;\n    background-color: #FFF7DD;\n    margin-left: -.2rem;\n    cursor: pointer;\n    border-radius: 0 2px 2px 0;\n    margin-bottom: 1px;\n}\n\n.copy-to-clipboard:hover {\n    background-color: #E8E2CD;\n}\n\npre .copy-to-clipboard {\n    position: absolute;\n    right: 4px;\n    top: 4px;\n    background-color: #4d5257;\n    color: #ccc;\n    border-radius: 2px;\n}\n\npre .copy-to-clipboard:hover {\n    background-color: #656c72;\n    color: #fff;\n}\n\n.parent-element {\n    -webkit-transform-style: preserve-3d;\n    -moz-transform-style: preserve-3d;\n    transform-style: preserve-3d;\n}\n\n#sidebar ul.topics>li>a .read-icon {\n    margin-top: 9px;\n}\n\n#sidebar ul {\n    list-style: none;\n    padding: 0;\n    margin: 0;\n}\n\n#sidebar #shortcuts li {\n    padding: 2px 0;\n    list-style: none;\n}\n\n#sidebar ul li .read-icon {\n    display: none;\n    float: right;\n    font-size: 13px;\n    min-width: 16px;\n    margin: 4px 0 0 0;\n    text-align: right;\n}\n\n#sidebar ul li.visited>a .read-icon {\n    color: #00bdf3;\n    display: inline;\n}\n\n#sidebar #shortcuts h3 {\n    font-family: \"Novacento Sans Wide\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    color: white;\n    margin-top: 1rem;\n    padding-left: 1rem;\n}\n\n#searchResults {\n    text-align: left;\n}\n\n/*# sourceMappingURL=theme.css.map */"
  },
  {
    "path": "docs/static/css/theme-mine.css",
    "content": "/* background behind the logo*/\n#header {\n    background: black;\n    border-color: black;\n}\n\n#header-wrapper {\n    background: black;\n    border-color: black;\n}\n\n#chapter p {\n    text-align: left;\n}\n\n.copy-to-clipboard {\n    background-image: none;\n    display: none;\n}\n\n#body img, #body .video-container {\n    margin: auto;\n    text-align: left;\n    display: inherit;\n}\n "
  },
  {
    "path": "docs/static/css/theme-white.css",
    "content": "body{\n    font-family: 'roboto,sans-serif';\n    letter-spacing: .33px;\n    font-weight: 400;\n    text-rendering: optimizeLegibility;\n    -webkit-font-smoothing: antialiased;\n}\n.wrap{\n    max-width: 1440px;\n    margin: 0 auto;\n    display: flex;\n}\n\nheader{\n    background-color: #F7F7FB;\n    height: 80px;\n}\n\nheader .wrap{\n    justify-content: space-between;\n    align-items: center;\n    height: 80px;\n    padding: 0 20px 0 20px;\n}\n\nheader li a{\n    color:#393C4E;\n}\n\nheader .select-style{\n    width: 80px;\n}\nheader .select-style svg{\n    fill:#000;\n}\n\nheader img{\n    height: 50px;\n}\n\nheader li{list-style: none;}\nheader .select-style select{\n    color:#000;\n}\n\n#body img,\n#body .video-container {\n    margin: auto;\n    text-align: left;\n    display: inherit;\n    max-width: 100%;\n    \n    /* set img size */\n}\n\n#sidebar{\n    width:350px;\n    position: sticky;\n    flex: 350px 0 0;\n    padding:0 16px 0 16px;\n    background-color: transparent;\n    bottom:initial;\n    font-weight: 400!important;\n    z-index: 2;\n}\n\n#sidebar .leftMenu{\n    overflow-y: auto;\n}\n\n#header-wrapper{\n    position:sticky;\n    background-color: #fff;\n    border-bottom: none;\n    padding:0;\n    top:0px;\n}\n\n.searchbox{\n    height: 48px;\n    background-color: #F7F8FA;\n    border-color: #F7F8FA;\n    border-radius: 8px;\n}\n\n.searchbox input{\n    height: 48px;\n    color:#000;\n    box-shadow: none;\n}\n\n.searchbox label,.searchbox span{\n    color:#6B6D7A;\n    top:10px;\n}\n.searchbox span:hover{\n    color:#6B6D7A;\n}\n\n#sidebar a{\n    color:#000;\n}\n\n#sidebar a:hover{\n    color:#F6651C;\n}\n\n#sidebar ul li a{\n   margin-bottom: .625rem;\n}\n\n#sidebar ul li.active > a{\n    color: #F6651C!important;\n}\n\n#sidebar ul.topics > li > a{\n    font-size: 1rem;\n}\n\n#sidebar .highlightable{\n    position:sticky;\n    top:48px;\n}\n\n#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active{\n    background-color: #fff;\n}\n\n#sidebar ul.topics > li > a b{\n    font-weight: 400;\n    opacity: 1;\n}\n\n#sidebar ul li i{\n    position: relative;\n    top:3px;\n}\n\n#sidebar a.padding{\n    display: block;\n    width: 224px;\n    height: 48px;\n    border-radius: 8px 8px 8px 8px;\n    opacity: 1;\n    border: 2px solid #3A49CF;\n    text-align: center;\n    line-height: 45px;\n    color:#3A49CF;\n    font-size: 16px;\n    margin:24px  auto 0;\n    font-weight: bold;\n}\n\n#sidebar a.padding:hover{\n    color:#F6651C;\n    border-color: #F6651C;\n}\n\n#body{\n    margin-left:0;\n    min-width: 15em;\n    flex-grow: 1;\n}\n\n#body .padding{padding:1rem;}\n\n#chapter p {\n    text-align: left;\n}\n\n#chapter #body-inner{\n    max-width: 95%;\n    \n}\n\n#body-inner{\n    padding-right: 250px;\n}\n\n#chapter img{\n    /* background-color: #F3F4F6;\n    padding:10px;\n    border-radius: 41px; */\n}\n\n#TableOfContents{\n    position: fixed;\n    left: 50%;\n    width: 230px;\n    transform: translateX(calc(85% + 280px));\n    transition: top .1s ease;\n    top:192px;\n    padding-left: 20px!important;\n}\n\n#TableOfContents.sticky{\n    top: 63px;\n}\n\n\n#TableOfContents li{\n    list-style: none;\n}\n#TableOfContents a.active{\n    color:#F6651C;\n}\n#TableOfContents>ul{font-size: 1rem;padding-left:0}\n#TableOfContents > ul > li > a{padding: 0;font-weight: bold;}\n#TableOfContents>ul>li{list-style: outside;}\n#TableOfContents>ul>li>a:before{\n    display: none;\n}\n#TableOfContents>ul>li:first-child{\n    margin-top:0;\n}\n#TableOfContents>ul>li>ul{\n    font-size: 0.875rem;\n    position: relative;\n    padding-left: 17px;\n}\n#TableOfContents>ul>li>ul:before{\n    content:' ';\n    border-left: 1px solid #C4C4C4;\n    position:absolute;\n    left:2px;\n    height: 100%;\n}\n#TableOfContents>ul>li>ul>li>a{\n    position: relative;\n}\n#TableOfContents>ul>li>ul>li>a.active{\n    color:#F6651C;\n}\n#TableOfContents>ul>li>ul>li>a.active::before{\n    border-color:#F6651C ;\n    background-color: #F6651C;\n}\n#TableOfContents>ul>li>ul>li>a::before{\n    content:'';\n    width: 10px;\n    height: 10px;\n    border-radius: 100%;\n    border:1px solid #C4C4C4;\n    position: absolute;\n    left:-20px;\n    top:3px;\n    background-color: #fff;\n}\n#TableOfContents>ul>li>ul>li>a:hover:before{\n    border-color:#F6651C ;\n    background-color: #F6651C;\n}\n#TableOfContents>ul li{\n    margin:1.5em 0 1em;\n}\n\n#chapter table em{font-style: normal;}\n\na{\n    color:#6B6D7A\n}\na:hover{\n    color: #F6651C;\n}\n#body a.highlight:after{\n    background-color: #F6651C;\n}\n\n#top-bar{\n    background-color: #F7F7FB;\n}\n\n#body #navigation{\n    max-width: 95%;\n    margin:0 auto 3rem;\n    display: flex;\n    justify-content: space-between;\n    padding-right:245px;\n}\n\n#chapter #body-inner{\n    padding-bottom: 0rem;\n    margin-bottom: 0rem;\n}\n\n#body .nav{\n    position:static;\n    width: 7rem;\n    font-size: 16px;\n    line-height: 26px;\n    font-weight: bold;\n    color:#3A49CF;\n}\n#body .nav-prev{\n    text-align: left;\n}\n#body .nav-prev i{padding-right: 7px;}\n#body .nav-next{\n    text-align: right;\n}\n#body .nav:hover{\n    background:transparent;\n}\n\n#body .nav i{\n    padding-top:3px;\n}\n\n\nh1, h2, h3, h4, h5, h6{font-weight: bold;font-family:'roboto,sans-serif' ;}\nh1{\n    text-align: left;\n}\n\nh2{\n    margin:2rem 0 1rem;\n}\nh2:first-of-type{\n    margin-top:0;\n}\n\ntable{\n    table-layout: fixed;\n}\n\ntable td,p,code{\n    word-break:break-all;\n    white-space: inherit;\n}\n\n.icon-1{\n    position:fixed;\n    top:659px;\n    width: 50px;\n    height: 24px;\n    left:50%;\n    background:url('../img/icon-1.png') no-repeat;\n    background-size: contain;\n    transform: translate(554px, 0);\n    animation: mymove 5s ease infinite;\n}\n.icon-2{\n    position: fixed;\n    top:862px;\n    left:50%;\n    width: 30px;\n    height: 30px;\n    background:url('../img/icon-2.png') no-repeat;\n    background-size: contain;\n    transform: translateX(-540px);\n    animation: mymove2 5s ease .5s infinite;\n}\n.icon-3{\n    position:fixed;\n    /* top:1020px; */\n    bottom:80px;\n    width: 150px;\n    height: 31px;\n    left:50%;\n    background:url('../img/icon-3.png') no-repeat;\n    background-size: contain;\n    transform: translateX(525px);\n    animation: mymove3 5s ease 1s infinite;\n}\n\n.change-theme{\n    height: 32px;\n    background:#111;\n    color: #fff;\n    line-height: 32px;\n}\n.change-theme .wrap{\n    justify-content: right;\n}\n.change-theme span{\n    margin:0 16px;\n    cursor: pointer;\n    font-size: 14px;\n}\n.change-theme span svg{\n    display: none;\n    vertical-align: middle;\n}\n.change-theme span.active{\n    position:relative;\n}\n.change-theme span.active svg{\n    display: inline-block;\n}\n.change-theme span.active.retro{\n    color:#F2EFDD;\n}\n.change-theme span.active.retro svg path{\n    fill: #F2EFDD;\n}\n.change-theme span.active.eyehelp{\n    color:#C7EBC9;\n}\n.change-theme span.active.eyehelp svg path{\n    fill: #C7EBC9;\n}\n.change-theme span.active.haitian{\n    color:#E5EDFF;\n}\n.change-theme span.active.haitian svg path{\n    fill: #E5EDFF;\n}\n.change-theme span.active.deep,.change-theme span.active.dark{\n    color:#65A4FF;\n}\n.change-theme span.active.deep svg path,.change-theme span.active.dark svg path{\n    fill: #65A4FF;\n}\n/* .change-theme span.active::before{\n    content: ' ';\n    width: 16px;\n    height: 16px;\n    position: absolute;\n    left:0;\n    top:7px;\n    background-image: url('../img/theme.svg');\n} */\n\n@media only all and (min-width: 48em) and (max-width: 89.99em) {\n    #TableOfContents{\n        right: 1rem;\n        transform: translateX(0);\n        left:auto;\n    }\n}\n@media only all and (min-width: 48em) and (max-width: 59.938em) {\n    body #chapter h1 {\n        font-size: 3rem;\n    }\n    #body-inner{padding-right: 0;}\n    #TableOfContents{\n        position: static;\n        transform: translateX(0);\n    }\n    #body #navigation{padding-right: 0;}\n    .icon-3,.icon-2,.icon-1{display: none;}\n}\n@media only all and (max-width: 59.938em){\n    #body #navigation{padding-right: 0;}\n}\n@media only all and (max-width: 47.938em) {\n    header .wrap{\n        padding: 0 20px;\n    }\n    header .wrap ul{\n        padding-left:30px;\n    }\n    .change-theme span{\n        margin:0 7px;\n    }\n    body #chapter h1 {\n        font-size: 2rem;\n    }\n    #sidebar{\n        position: fixed;\n        left:-300px;\n        width: 300px;\n        padding-left: 16px;\n        background-color: #fff;\n    }\n\n    .sidebar-hidden #body{\n        margin-left: 300px;\n    }\n\n    #body{\n        min-width: 8rem;\n    }\n\n    #body-inner{padding-right: 0;}\n    #TableOfContents{\n        position: static;\n        transform: translateX(0);\n    }\n    .icon-3,.icon-2,.icon-1{display: none;}\n\n    .retro-theme #sidebar{\n        background-color: #F2EFDD;\n    }\n    .eyehelp-theme #sidebar{\n        background-color: #C7EBC9;\n    }\n    .haitian-theme #sidebar{\n        background-color: #E5EDFF;\n    }\n    .deep-theme #sidebar{\n        background-color: #15202F;\n    }\n    .dark-theme #sidebar{\n        background-color: #171717;\n    }\n\n}\n\n@keyframes mymove {\n    0%{\n        transform: translate(554px, 0);\n    }\n    50%{\n        transform: translate(554px, 20px);\n    }\n    100%{\n        transform: translate(554px, 0);\n    }\n}\n\n@keyframes mymove2 {\n    0%{\n        transform: translate(-540px, 0);\n    }\n    50%{\n        transform: translate(-540px, 20px);\n    }\n    100%{\n        transform: translate(-540px, 0);\n    }\n}\n\n@keyframes mymove3 {\n    0%{\n        transform: translate(525px, 0);\n    }\n    50%{\n        transform: translate(525px, 20px);\n    }\n    100%{\n        transform: translate(525px, 0);\n    }\n}\n\n/*change theme*/\n/*retro*/\n.retro-theme{\n    background-color: #F2EFDD;\n}\n.retro-theme header{\n    background-color: #F8F5EA;\n}\n.retro-theme #header-wrapper, .retro-theme .searchbox{\n    background-color: #F8F5EA;\n    border-radius: 8px;\n    border-color: #F8F5EA;\n}\n.retro-theme #sidebar ul.topics > li.parent,.retro-theme #sidebar ul.topics > li.active{\n    background-color: #F2EFDD;\n}\n.retro-theme #sidebar ul li.active > a{\n    background-color: #F2EFDD;\n}\n.retro-theme #top-bar{\n    background-color: #F8F5EA;\n}\n.retro-theme #TableOfContents>ul>li>ul>li>a::before{\n    background-color: #F8F5EA;\n}\n.retro-theme th{\n    background-color: #F8F5EA;\n}\n.eyehelp-theme table,.retro-theme td,.retro-theme blockquote{\n    border-color: #dfdcdc;\n}\n/*eyehelp*/\n.eyehelp-theme{\n    background-color: #C7EBC9;\n}\n.eyehelp-theme header{\n    background-color: #D6F6D7;\n}\n.eyehelp-theme #header-wrapper, .eyehelp-theme .searchbox{\n    background-color: #D6F6D7;\n    border-radius: 8px;\n    border-color: #D6F6D7;\n}\n.eyehelp-theme #sidebar ul.topics > li.parent,.eyehelp-theme #sidebar ul.topics > li.active{\n    background-color: #C7EBC9;\n}\n.eyehelp-theme #sidebar ul li.active > a{\n    background-color: #C7EBC9;\n}\n.eyehelp-theme #top-bar{\n    background-color: #D6F6D7;\n}\n.eyehelp-theme #TableOfContents>ul>li>ul>li>a::before{\n    background-color: #D6F6D7;\n}\n.eyehelp-theme th{\n    background-color: #D6F6D7;\n}\n.eyehelp-theme table,.eyehelp-theme td,.eyehelp-theme blockquote{\n    border-color: #c1c1c1;\n}\n/*haitian*/\n.haitian-theme{\n    background-color: #E5EDFF;\n}\n.haitian-theme header{\n    background-color: #EDF2FF;\n}\n.haitian-theme #header-wrapper, .haitian-theme .searchbox{\n    background-color: #EDF2FF;\n    border-radius: 8px;\n    border-color: #EDF2FF;\n}\n.haitian-theme #sidebar ul.topics > li.parent,.haitian-theme #sidebar ul.topics > li.active{\n    background-color: #E5EDFF;\n}\n.haitian-theme #sidebar ul li.active > a{\n    background-color: #E5EDFF;\n}\n.haitian-theme #top-bar{\n    background-color: #EDF2FF;\n}\n.haitian-theme #TableOfContents>ul>li>ul>li>a::before{\n    background-color: #EDF2FF;\n}\n.haitian-theme th{\n    background-color: #EDF2FF;\n}\n.haitian-theme table,.haitian-theme td,.haitian-theme blockquote{\n    border-color: #c1c1c1;\n}\n/*Deep*/\n.deep-theme{\n    background-color: #15202F;\n    color: #b8c5d9 !important;\n}\n.deep-theme header{\n    background-color: #1B283B;\n}\n.deep-theme header img{\n    height: 50px;\n}\n.deep-theme #header-wrapper, .deep-theme .searchbox{\n    background-color: #1B283B;\n    border-radius: 8px;\n    border-color: #1B283B;\n}\n.deep-theme #sidebar ul.topics > li.parent,.deep-theme #sidebar ul.topics > li.active{\n    background-color: #15202F;\n}\n.deep-theme #sidebar ul li.active > a{\n    background-color: #15202F;\n}\n.deep-theme #top-bar{\n    background-color: #1B283B;\n}\n.deep-theme #TableOfContents>ul>li>ul>li>a::before{\n    background-color: #1B283B;\n}\n.deep-theme th{\n    background-color: #1B283B;\n}\n.deep-theme table,.deep-theme td,.deep-theme blockquote{\n    border-color: #c1c1c1;\n}\n.deep-theme #body img{\n    background-color: #EDF2FF;\n    border-radius: 20px;\n}\n.deep-theme h1,\n.deep-theme h2,\n.deep-theme h3,\n.deep-theme h4,\n.deep-theme h5,\n.deep-theme h6,\n.deep-theme #sidebar a,\n.deep-theme a,\n.deep-theme .searchbox input,\n.deep-theme .select-style select{\n    color: #b8c5d9\n}\n/*Dark*/\n.dark-theme{\n    background-color: #171717;\n    color: #B1B1B1 !important;\n}\n.dark-theme header{\n    background-color: #202020;\n}\n.dark-theme header img{\n    height: 50px;\n}\n.dark-theme #header-wrapper, .dark-theme .searchbox{\n    background-color: #202020;\n    border-radius: 8px;\n    border-color: #202020;\n}\n.dark-theme #sidebar ul.topics > li.parent,.dark-theme #sidebar ul.topics > li.active{\n    background-color: #171717;\n}\n.dark-theme #sidebar ul li.active > a{\n    background-color: #171717;\n}\n.dark-theme #top-bar{\n    background-color: #202020;\n}\n.dark-theme #TableOfContents>ul>li>ul>li>a::before{\n    background-color: #202020;\n}\n.dark-theme th{\n    background-color: #202020;\n}\n.dark-theme table,.dark-theme td,.dark-theme blockquote{\n    border-color: #c1c1c1;\n}\n.dark-theme #body img{\n    background-color: #EDF2FF;\n    border-radius: 20px;\n}\n.dark-theme h1,\n.dark-theme h2,\n.dark-theme h3,\n.dark-theme h4,\n.dark-theme h5,\n.dark-theme h6,\n.dark-theme #sidebar a,\n.dark-theme a,\n.dark-theme .searchbox input,\n.dark-theme .select-style select{\n    color: #B1B1B1\n}\n\n\n"
  },
  {
    "path": "docs/static/data/chart.js",
    "content": "var chartData = {\n    \"compareQuery\": {\n        labels: [\"50\", \"100\", \"200\", \"300\", \"600\"],\n        datasets: [\n           {\n                label: \"JDBC\",\n                data: [1812, 3828, 5217, 7239, 7169]\n            }, {\n                label: \"Sharding-JDBC\",\n                data: [1591, 2547, 5062, 7284, 7151]\n            }\n        \n        ]\n    },\"compareInsert\": {\n        labels: [\"50\", \"100\", \"200\", \"300\", \"600\"],\n        datasets: [\n            {\n                label: \"JDBC\",\n                data: [2520, 5860, 6420, 6200, 6250]\n            },{\n                label: \"Sharding-JDBC\",\n                data: [2410, 4230, 5445, 5603, 5642]\n            }\n        \n        ]\n    },\"compareUpdate\": {\n        labels: [\"50\", \"100\", \"200\", \"300\", \"600\"],\n        datasets: [\n            {\n                label: \"JDBC\",\n                data: [2430, 5712, 6557, 7773, 7561]\n            },{\n                label: \"Sharding-JDBC\",\n                data: [2059, 2715, 4770, 7280, 7210]\n            }\n        \n        ]\n    }, \"singleAndDubbleQuery\": {\n        labels: [\"50\", \"100\", \"200\", \"300\", \"600\"],\n        datasets: [\n            {\n                label: \"双库\",\n                data: [3724, 6246, 11480, 13107, 13960]\n            },{\n                label: \"单库\",\n                data: [1591, 2547, 5062, 7284, 7151]\n            }\n        \n        ]\n    },\"singleAndDubbleInsert\": {\n        labels: [\"50\", \"100\", \"200\", \"300\", \"600\"],\n        datasets: [\n            {\n                label: \"双库\",\n                data: [4021, 6807, 7911, 8109, 7619]\n            },{\n                label: \"单库\",\n                data: [2410, 4230, 5445, 5603, 5642]\n            }\n        \n        ]\n    },\"singleAndDubbleUpdate\": {\n        labels: [\"50\", \"100\", \"200\", \"300\", \"600\"],\n        datasets: [\n            {\n                label: \"双库\",\n                data: [2190, 4464, 9039, 10144, 11970]\n            },{\n                label: \"单库\",\n                data: [2059, 2715, 4770, 7280, 7210]\n            }\n        ]\n    },\"fatigueTest\": {\n        labels: [\"0\", \"1小时\", \"2小时\", \"3小时\", \"4小时\", \"5小时\", \"6小时\", \"7小时\", \"8小时\"],\n        datasets: [\n            {\n                label: \"jvm堆大小\",\n                data: [0, 567, 533, 587, 523, 546, 577 ,534,577]\n            }\n        ]\n    }\n};\n\nvar charStyle = [\n    \n    {\n        backgroundColor: \"rgba(246,179,107,0.2)\",\n        borderColor: \"rgba(246,179,107,1)\",\n        pointBorderColor: \"rgba(246,179,107,1)\",\n        pointBackgroundColor: \"#fff\",\n        pointBorderWidth: 1,\n        pointHoverRadius: 5,\n        pointHoverBackgroundColor: \"rgba(246,179,107,1)\",\n        pointHoverBorderColor: \"rgba(246,179,107,1)\",\n        pointHoverBorderWidth: 2\n    },\n    {\n        backgroundColor: \"rgba(61,134,198,0.2)\",\n        borderColor: \"rgba(61,134,198,1)\",\n        pointBorderColor: \"rgba(61,134,198,1)\",\n        pointBackgroundColor: \"#fff\",\n        pointBorderWidth: 1,\n        pointHoverRadius: 5,\n        pointHoverBackgroundColor: \"rgba(61,134,198,1)\",\n        pointHoverBorderColor: \"rgba(61,134,198,1)\",\n        pointHoverBorderWidth: 2\n    }\n];"
  },
  {
    "path": "docs/themes/hugo-theme-learn/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Grav\nCopyright (c) 2016 MATHIEU CORNIC\nCopyright (c) 2017 Valere JEANTET\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/README.md",
    "content": "# Hugo Learn Theme\n\nThis repository contains a theme for [Hugo](https://gohugo.io/), based on great [Grav Learn Theme](http://learn.getgrav.org/).\n\nVisit the [theme documentation](https://learn.netlify.com/en/) to see what is going on. It is actually built with this theme.\n\n## Main features\n\n- Automatic Search\n- Multilingual mode\n- Unlimited menu levels\n- Automatic next/prev buttons to navigate through menu entries\n- Image resizing, shadow…\n- Attachments files\n- List child pages\n- Mermaid diagram (flowchart, sequence, gantt)\n- Customizable look and feel and themes variants\n- Buttons, Tip/Note/Info/Warning boxes, Expand\n\n## Installation\n\nNavigate to your themes folder in your Hugo site and use the following commands:\n\n```\n$ cd themes\n$ git clone https://github.com/matcornic/hugo-theme-learn.git\n```\n\nCheck that your Hugo version is minimum `0.25` with `hugo version`.\n\n![Overview](https://github.com/matcornic/hugo-theme-learn/raw/master/images/tn.png)\n\n## Usage\n\n- [Visit the documentation](https://learn.netlify.com/en/)\n\n## Download old versions (prior to 2.0.0)\n\nIf you need old version for compatibility purpose, either download [theme source code from releases](https://github.com/matcornic/hugo-theme-learn/releases) or use the right git tag. For example, with `1.1.0` \n\n- Direct download way: https://github.com/matcornic/hugo-theme-learn/archive/1.1.0.zip\n- Git way:\n\n```shell\ncd themes/hugo-theme-learn\ngit checkout tags/1.1.0\n```\n\nFor both solutions, the documentation is available at https://github.com/matcornic/hugo-theme-learn/releases/download/1.1.0/hugo-learn-doc-1.1.0.zip\n\n## Credits\n\nMany thanks to [@vjeantet](https://github.com/vjeantet/) for the fork [docdock](https://github.com/vjeantet/hugo-theme-docdock). The v2 of this theme is mainly based on his work !\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/archetypes/chapter.md",
    "content": "+++\ntitle = \"{{ replace .TranslationBaseName \"-\" \" \" | title }}\"\ndate = {{ .Date }}\nweight = 5\nchapter = true\npre = \"<b>X. </b>\"\n+++\n\n### Chapter X\n\n# Some Chapter title\n\nLorem Ipsum."
  },
  {
    "path": "docs/themes/hugo-theme-learn/archetypes/default.md",
    "content": "+++\ntitle = \"{{ replace .TranslationBaseName \"-\" \" \" | title }}\"\ndate =  {{ .Date }}\nweight = 5\n+++\n\nLorem Ipsum."
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/LICENSE.md",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 MATHIEU CORNIC\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/config.toml",
    "content": "baseURL = \"localhost:1313/test\"\nlanguageCode = \"en-US\"\ndefaultContentLanguage = \"en\"\n\ntitle = \"Hugo Learn Documentation\"\ntheme = \"hugo-theme-learn\"\nthemesdir = \"../..\"\nmetaDataFormat = \"yaml\"\ndefaultContentLanguageInSubdir= true\n\n[params]\n  editURL = \"https://github.com/matcornic/hugo-theme-learn/edit/master/exampleSite/content/\"\n  description = \"Documentation for Hugo Learn Theme\"\n  author = \"Mathieu Cornic\"\n  showVisitedLinks = true\n\n[outputs]\nhome = [ \"HTML\", \"RSS\", \"JSON\"]\n\n[Languages]\n[Languages.en]\ntitle = \"Documentation for Hugo Learn Theme\"\nweight = 1\nlanguageName = \"English\"\n\n[[Languages.en.menu.shortcuts]] \nname = \"<i class='fa fa-fw fa-github'></i> Github repo\"\nidentifier = \"ds\"\nurl = \"https://github.com/matcornic/hugo-theme-learn\"\nweight = 10\n\n[[Languages.en.menu.shortcuts]]\nname = \"<i class='fa fa-fw fa-camera'></i> Showcases\"\nurl = \"showcase\"\nweight = 11\n\n[[Languages.en.menu.shortcuts]]\nname = \"<i class='fa fa-fw fa-bookmark'></i> Hugo Documentation\"\nidentifier = \"hugodoc\"\nurl = \"https://gohugo.io/\"\nweight = 20\n\n[[Languages.en.menu.shortcuts]]\nname = \"<i class='fa fa-fw fa-bullhorn'></i> Credits\"\nurl = \"/credits\"\nweight = 30\n\n[Languages.fr]\ntitle = \"Documentation du thème Hugo Learn\"\nweight = 2\nlanguageName = \"Français\"\n\n[[Languages.fr.menu.shortcuts]]\nname = \"<i class='fa fa-fw fa-github'></i> Repo Github\"\nidentifier = \"ds\"\nurl = \"https://github.com/matcornic/hugo-theme-learn\"\nweight = 10\n\n[[Languages.fr.menu.shortcuts]]\nname = \"<i class='fa fa-fw fa-camera'></i> Vitrine\"\nurl = \"/showcase\"\nweight = 11\n\n[[Languages.fr.menu.shortcuts]]\nname = \"<i class='fa fa-fw fa-bookmark'></i> Documentation Hugo\"\nidentifier = \"hugodoc\"\nurl = \"https://gohugo.io/\"\nweight = 20\n\n[[Languages.fr.menu.shortcuts]]\nname = \"<i class='fa fa-fw fa-bullhorn'></i> Crédits\"\nurl = \"/credits\"\nweight = 30\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/_index.en.md",
    "content": "---\ntitle: \"Learn Theme for Hugo\"\n---\n\n# Hugo learn theme\n\n[Hugo-theme-learn](http://github.com/matcornic/hugo-theme-learn) is a theme for [Hugo](https://gohugo.io/), a fast and modern static website engine written in Go. Where Hugo is often used for blogs, this multilingual-ready theme is **fully designed for documentation**.\n\nThis theme is a partial porting of the [Learn theme](http://learn.getgrav.org/) of [Grav](https://getgrav.org/), a modern flat-file CMS written in PHP.\n\n{{% notice tip %}}Learn theme works with a _page tree structure_ to organize content : All contents are pages, which belong to other pages. [read more about this]({{%relref \"cont/pages/_index.md\"%}}) \n{{% /notice %}}\n\n## Main features\n\n* [Automatic Search]({{%relref \"basics/configuration/_index.md#activate-search\" %}})\n* [Multilingual mode]({{%relref \"cont/i18n/_index.md\" %}})\n* **Unlimited menu levels**\n* **Automatic next/prev buttons to navigate through menu entries**\n* [Image resizing, shadow...]({{%relref \"cont/markdown.en.md#images\" %}})\n* [Attachments files]({{%relref \"shortcodes/attachments.en.md\" %}})\n* [List child pages]({{%relref \"shortcodes/children/_index.md\" %}})\n* [Mermaid diagram]({{%relref \"shortcodes/mermaid.en.md\" %}}) (flowchart, sequence, gantt)\n* [Customizable look and feel and themes variants]({{%relref \"basics/style-customization/_index.md\"%}})\n* [Buttons]({{%relref \"shortcodes/button.en.md\" %}}), [Tip/Note/Info/Warning boxes]({{%relref \"shortcodes/notice.en.md\" %}}), [Expand]({{%relref \"shortcodes/expand.en.md\" %}})\n\n![Screenshot](https://github.com/matcornic/hugo-theme-learn/raw/master/images/screenshot.png?width=40pc&classes=shadow)\n\n## Contribute to this documentation\nFeel free to update this content, just click the **Edit this page** link displayed on top right of each page, and pullrequest it\n\n{{% notice info %}}\nYour modification will be deployed automatically when merged.\n{{% /notice %}}\n\n## Documentation website\nThis current documentation has been statically generated with Hugo with a simple command : `hugo -t hugo-theme-learn` -- source code is [available here at GitHub](https://github.com/matcornic/hugo-theme-learn)\n\n{{% notice note %}}\nAutomatically published and hosted thanks to [Netlify](https://www.netlify.com/). Read more about [Automated HUGO deployments with Netlify](https://www.netlify.com/blog/2015/07/30/hosting-hugo-on-netlifyinsanely-fast-deploys/)\n{{% /notice %}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/_index.fr.md",
    "content": "---\ntitle: \"Learn Theme for Hugo\"\n---\n\n# Thème Hugo learn\n\n[Hugo-theme-learn](http://github.com/matcornic/hugo-theme-learn) est un thème pour [Hugo](https://gohugo.io/), un générateur de site statique, rapide et modern, écrit en Go. Tandis que Hugo est souvent utilisé pour des blogs, ce thème multi-langue est **entièrement conçu pour la documentation**.\n\nCe thème est un portage partiel du [thème Learn](http://learn.getgrav.org/) de [Grav](https://getgrav.org/), un CMS modern écrit en PHP.\n\n{{% notice tip %}}Le thème Learn fonctionne grâce à la structure de page aborescentes pour organiser le contenu: tous les contenus sont des pages qui appartiennent à d'autres pages. [Plus d'infos]({{%relref \"cont/pages/_index.md\"%}}) \n{{% /notice %}}\n\n## Fonctionnalités principales\n\n* [Recherche automatique]({{%relref \"basics/configuration/_index.md#activer-recherche\" %}})\n* [Mode multi-langue]({{%relref \"cont/i18n/_index.md\" %}})\n* **Nombre de niveau infini dans le menu**\n* **Boutons suivant/précédent automatiquement générés pour naviguer entre les items du menu**\n* [Taille d'image, ombres...]({{%relref \"cont/markdown.fr.md#images\" %}})\n* [Fichiers joints]({{%relref \"shortcodes/attachments.fr.md\" %}})\n* [Lister les pages filles]({{%relref \"shortcodes/children/_index.md\" %}})\n* [Diagrammes Mermaid]({{%relref \"shortcodes/mermaid.fr.md\" %}}) (flowchart, sequence, gantt)\n* [Style configurable and variantes de couleurs]({{%relref \"basics/style-customization/_index.md\"%}})\n* [Boutons]({{%relref \"shortcodes/button.fr.md\" %}}), [Messages Astuce/Note/Info/Attention]({{%relref \"shortcodes/notice.fr.md\" %}}), [Expand]({{%relref \"shortcodes/expand.fr.md\" %}})\n\n![Screenshot](https://github.com/matcornic/hugo-theme-learn/raw/master/images/screenshot.png?width=40pc&classes=shadow)\n\n## Contribuer à cette documentation\n\nN'hésitez pas à mettre à jour ce contenu en cliquant sur le lien **Modifier cette page** en haut de chaque page, et créer la Pull Request associée.\n\n{{% notice info %}}\nVotre modification sera déployée automatiquement quand elle sera mergée.\n{{% /notice %}}\n\n## Site de documentation\n\nCette documentation statique a été générée avec Hugo avec une simple commande : `hugo -t hugo-theme-learn` -- le code source est [disponible sur Github](https://github.com/matcornic/hugo-theme-learn)\n\n{{% notice note %}}\nLe site est auomatiquement publié et hébergé par [Netlify](https://www.netlify.com/). Plus d'infos sur le [déploiement de site Hugo avec Netlify](https://www.netlify.com/blog/2015/07/30/hosting-hugo-on-netlifyinsanely-fast-deploys/)(En anglais)\n{{% /notice %}}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/basics/_index.en.md",
    "content": "---\ntitle: Basics\nweight: 5\npre: \"<b>1. </b>\"\nchapter: true\n---\n\n### Chapter 1\n\n# Basics\n\nDiscover what this Hugo theme is all about and the core-concepts behind it.\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/basics/_index.fr.md",
    "content": "---\ntitle: Démarrage\nweight: 5\npre: \"<b>1. </b>\"\nchapter: true\n---\n\n### Chapitre 1\n\n# Démarrage\n\nDécouvrez comment utiliser ce thème Hugo et apprenez en les concepts\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/basics/configuration/_index.en.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Configuration\nweight: 20\n---\n\n## Global site parameters\n\nOn top of [Hugo global configuration](https://gohugo.io/overview/configuration/), **Hugo-theme-learn** lets you define the following parameters in your `config.toml` (here, values are default).\n\nNote that some of these parameters are explained in details in other sections of this documentation.\n\n```toml\n[params]\n  # Prefix URL to edit current page. Will display an \"Edit this page\" button on top right hand corner of every page. \n  # Useful to give opportunity to people to create merge request for your doc.\n  # See the config.toml file from this documentation site to have an example.\n  editURL = \"\"\n  # Author of the site, will be used in meta information\n  author = \"\"\n  # Description of the site, will be used in meta information\n  description = \"\"\n  # Shows a checkmark for visited pages on the menu\n  showVisitedLinks = false\n  # Disable search function. It will hide search bar\n  disableSearch = false\n  # Javascript and CSS cache are automatically busted when new version of site is generated. \n  # Set this to true to disable this behavior (some proxies don't handle well this optimization)\n  disableAssetsBusting = false\n  # Set this to true to disable copy-to-clipboard button for inline code.\n  disableInlineCopyToClipBoard = false\n  # A title for shortcuts in menu is set by default. Set this to true to disable it. \n  disableShortcutsTitle = false\n  # When using mulitlingual website, disable the switch language button.\n  disableLanguageSwitchingButton = false\n  # Order sections in menu by \"weight\" or \"title\". Default to \"weight\"\n  ordersectionsby = \"weight\"\n  # Change default color scheme with a variant one. Can be \"red\", \"blue\", \"green\".\n  themeVariant = \"\"\n```\n\n## Activate search\n\nIf not already present, add the follow lines in the same `config.toml` file.\n\n```toml\n[outputs]\nhome = [ \"HTML\", \"RSS\", \"JSON\"]\n```\n\nLearn theme uses the last improvement available in hugo version 20+ to generate a json index file ready to be consumed by lunr.js javascript search engine.\n\n> Hugo generate lunrjs index.json at the root of public folder. \n> When you build the site with `hugo server`, hugo generates it internally and of course it doesn’t show up in the filesystem\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/basics/configuration/_index.fr.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Configuration\nweight: 20\n---\n\n## Paramètres globaux du site\n\nEn plus de la [configuration globale d'Hugo](https://gohugo.io/overview/configuration/), **Hugo-theme-learn** vous permet de définir les paramètres suivant dans votre fichier `config.toml` (ci-dessous sont affichées les valeurs par défaut).\n\nNotez que certains de ces paramètres sont expliqués en détails dans d'autres sections de cette documentation.\n\n```toml\n[params]\n  # L'URL préfixe pour éditer la page courante. Ce paramètre affichera un bouton \"Modifier cette page\" on haut de de chacune des pages.\n  # Pratique pour donner les possibilité à vos utilisateurs de créer une merge request pour votre doc.\n  # Allez voir le fichier config.toml de cette documentation pour avoir un exemple.\n  editURL = \"\"\n  # Autheur du site, est utilisé dans les informations meta\n  author = \"\"\n  # Description du site, est utilisé dans les informations meta\n  description = \"\"\n  # Affiche une icône lorsque la page a été visitée\n  showVisitedLinks = false\n  # Désactive la fonction de recherche. Une valeur à true cache la barre de recherche.\n  disableSearch = false\n  # Par défaut, le cache Javascript et CSS est automatiquement vidé lorsqu'une nouvelle version du site est générée. \n  # Utilisez ce paramètre lorsque vous voulez désactiver ce comportement (c'est parfois incompatible avec certains proxys)\n  disableAssetsBusting = false\n  # Utilisez ce paramètre pour désactiver le bouton copy-to-clipboard pour le code formatté sur une ligne.\n  disableInlineCopyToClipBoard = false\n  # Un titre est défini par défaut lorsque vous utilisez un raccourci dans le menu. Utilisez ce paramètre pour le cacher. \n  disableShortcutsTitle = false\n  # Quand vous utilisez un site multi-langue, utilisez ce paramètre pour désactiver le bouton de changement de langue.\n  disableLanguageSwitchingButton = false\n  # Ordonne les sections dans menu par poids (\"weight\") ou titre (\"title\"). Défaut à \"weight\"\n  ordersectionsby = \"weight\"\n  # Utilisez ce paramètre pour modifier le schéma de couleur du site. Les valeurs par défaut sont \"red\", \"blue\", \"green\".\n  themeVariant = \"\"\n```\n\n## Activer la recherche {#activer-recherche}\n\nSi ce n'est pas déjà présent, ajoutez les lignes suivantes dans le fichier `config.toml`.\n\n```toml\n[outputs]\nhome = [ \"HTML\", \"RSS\", \"JSON\"]\n```\n\nLe thème *Learn* utilise les dernières amélioraions d'Hugo pour générer un fichier d'index JSON, prêt à être consommé par le moteur de recherche lunr.js.\n\n> Hugo génère lunrjs index.json à la racine du dossier `public`. \n> Quand vous générez le site avec `hugo server`, Hugo génère le fichier en mémoire, il n'est donc pas disponible sur le disque."
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/basics/installation/_index.en.md",
    "content": "---\ntitle: Installation\nweight: 15\n---\n\nThe following steps are here to help you initialize your new website. If you don't know Hugo at all, we strongly suggest you to train by following this [great documentation for beginners](https://gohugo.io/overview/quickstart/).\n\n## Create your project\n\nHugo provides a `new` command to create a new website.\n\n```\nhugo new site <new_project>\n```\n\n## Install the theme\n\nInstall the **Hugo-theme-learn** theme by following [this documentation](https://gohugo.io/themes/installing/)\n\nThe theme's repository is: https://github.com/matcornic/hugo-theme-learn.git\n\nAlternatively, you can [download the theme as .zip](https://github.com/matcornic/hugo-theme-learn/archive/master.zip) file and extract it in the themes directory\n\n## Basic configuration\n\nWhen building the website, you can set a theme by using `--theme` option. We suggest you to edit your configuration file and set the theme by default. By the way, add requirements for search functionnality to be enabled.\n\n```toml\n# Change the default theme to be use when building the site with Hugo\ntheme = \"hugo-theme-learn\"\n\n# For search functionnality\n[outputs]\nhome = [ \"HTML\", \"RSS\", \"JSON\"]\n```\n\n## Create your first chapter page\n\nChapters are pages containg other child pages. It has a special layout style and usually just contains a _chapter name_, the _title_ and a _brief abstract_ of the section.\n\n```\n### Chapter 1\n\n# Basics\n\nDiscover what this Hugo theme is all about and the core-concepts behind it.\n```\n\nrenders as \n\n![A Chapter](/basics/installation/images/chapter.png?classes=shadow&width=60pc)\n\n**Hugo-theme-learn** provides archetypes to create skeletons for your website. Begin by creating your first chapter page with the following command\n\n```\nhugo new --kind chapter basics/_index.md\n```\n\nBy opening the given file, you should see the property `chapter=true` on top, meaning this page is a _chapter_.\n\nBy default all chapters and pages are created as draft. If you want to render these pages, remove the property `draft: true` from the metadata.\n\n## Create your first content pages\n\nThen, create content pages inside the previous chapter. Here are two ways to create content in the chapter :\n\n```\nhugo new basics/first-content.md\nhugo new basics/second-content/_index.md\n```\n\nFeel free to edit thoses files by adding some sample content and replacing `title` value in the beginning of the files. \n\n## Launching the website locally\n\nLaunch the following command:\n\n```\nhugo serve\n```\n\nGo to `http://localhost:1313`\n\nYou should notice three things:\n\n1. You have a left **Basics** menu, containing two submenus with names equals to `title` properties in previously created files.\n2. The home page explains you to how to customize it. Follow the instructions.\n3. With `hugo serve` command, the page refresh as soon as you save a file. Neat !\n\n## Build the website\n\nWhen your site is ready to deploy, launch the following command:\n\n```\nhugo\n```\n\nA `public` folder has been generated, containing all statics content and assets for your website. It can now be deployed on any web server !\n\n{{% notice note %}}\nThis website can be automatically published and hosted with [Netlify](https://www.netlify.com/) (Read more about [Automated HUGO deployments with Netlify](https://www.netlify.com/blog/2015/07/30/hosting-hugo-on-netlifyinsanely-fast-deploys/)). Alternatively, you can use [Github pages](https://gohugo.io/hosting-and-deployment/hosting-on-github/)\n{{% /notice %}}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/basics/installation/_index.fr.md",
    "content": "---\ntitle: Installation\nweight: 15\n---\n\nLes étapes suivantes sont là pour vous aider à initialiser votre site. Si vous ne connaissez pas du tout Hugo, il est fortement conseillé de vous entrainer en suivant ce [super tuto pour débutants](https://gohugo.io/overview/quickstart/).\n\n## Créer votre projet\n\nHugo fournit une commande `new` pour créer un nouveau site.\n\n```\nhugo new site <new_project>\n```\n\n## Installer le thème\n\nInstaller le thème **Hugo-theme-learn** en suivant [cette documentation](https://gohugo.io/themes/installing/)\n\nLe repo du thème est : https://github.com/matcornic/hugo-theme-learn.git\n\nSinon, vous pouvez [télécharger le thème sous forme d'un fichier .zip](https://github.com/matcornic/hugo-theme-learn/archive/master.zip) et extrayez le dans votre dossier de thèmes.\n\n## Configuration simple\n\nLorsque vous générez votre site, vous pouvez définir un thème en utilisant l'option `--theme`. Il est conseillé de modifier votre fichier de configuration `config.toml` and définir votre thème par défaut. En passant, ajoutez les prérequis à l'utilisation de la fonctionnalité de recherche.\n\n```toml\n# Modifiez le thème pour qu'il soit utilisé par défaut à chaque génération de site.\ntheme = \"hugo-theme-learn\"\n\n# Pour la fonctionnalité de recherche\n[outputs]\nhome = [ \"HTML\", \"RSS\", \"JSON\"]\n```\n\n## Créer votre première page chapitre\n\nLes *chapitres* sont des pages contenant d'autre pages filles. Elles ont un affichage spécial et contiennent habituellement juste un _nom_ de chapitre, le _titre_ et un _résumé_ de la section.\n\n```\n### Chapitre 1\n\n# Démarrage\n\nDécouvrez comment utiliser ce thème Hugo et apprenez en les concepts\n```\n\ns'affiche comme\n\n![Un chapitre](/basics/installation/images/chapter.png?classes=shadow&width=60pc)\n\n**Hugo-theme-learn** fournit des archétypes pour créer des squelettes pour votre site. Commencez par créer votre premier chapitre avec la commande suivante:\n\n```\nhugo new --kind chapter basics/_index.md\n```\n\nEn ouvrant le fichier généré, vous devriez voir la propriété `chapter=true` en haut, paramètre quit définit que le page est un _chapitre_.\n\n## Créer votre première page\n\nPuis, créez votre premier page dans le chapitre précédent. Pour ce faire, il existe deux possibilités :\n\n```\nhugo new basics/first-content.md\nhugo new basics/second-content/_index.md\n```\n\nN'hésitez pas à éditer ces fichiers en ajoutant des exemple de contenu et en remplaçant le paramètre `title` au début du fichier. \n\n## Lancer le site localement\n\nLancez la commande suivante :\n\n```\nhugo serve\n```\n\nSe rendre sur `http://localhost:1313`\n\nVous devriez voir trois choses:\n\n1. Vous avez un menu **Basics** à gauche, qui contient deux sous-menu avec des noms égal au paramètre `title` des fichiers précédemment générés.\n2. La page d'accueil vous explique comment la modifier. Suivez les instructions.\n3. Avec la commande `hugo serve`, la page se rafraichit automatiquement à chaque fois que vous sauvegardez. Super !\n\n## Générez le site\n\nQuand votre site est prêt à être déployé, lancez la commande suivante:\n\n```\nhugo\n```\n\nUn dossier `public` a été généré. Il contient tout le contenu statique et les ressources nécessaires pour votre site. Votre site peut maintenant être déployé en utilisant n'importe quel serveur !\n\n{{% notice note %}}\nCe site peut être automatiquement publié et hébergé avec [Netlify](https://www.netlify.com/) ([Plus d'infos](https://www.netlify.com/blog/2015/07/30/hosting-hugo-on-netlifyinsanely-fast-deploys/)). Sinon, vous pouvez utiliser les [Github pages](https://gohugo.io/hosting-and-deployment/hosting-on-github/)\n{{% /notice %}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/basics/requirements/_index.en.md",
    "content": "---\ntitle: Requirements\nweight: 10\ndisableToc: true\n---\n\nThanks to the simplicity of Hugo, this page is as empty as this theme needs requirements.\n\nJust download latest version of [Hugo binary (> 0.25)](https://gohugo.io/getting-started/installing/) for your OS (Windows, Linux, Mac) : it's that simple.\n\n![Magic](/basics/requirements/images/magic.gif?classes=shadow)\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/basics/requirements/_index.fr.md",
    "content": "---\ntitle: Prérequis\nweight: 10\ndisableToc: true\n---\n\nGrâce à la simplicité d'Hugo, cette page est vide car il n'y a quasi pas de prérequis pour utiliser le thème.\n\nTéléchargez la dernière version du [binaire Hugo (> 0.25)](https://gohugo.io/getting-started/installing/) pour votre Système d'exploitation (Windows, Linux, Mac) : et c'est tout !\n\n![Magic](/basics/requirements/images/magic.gif?classes=shadow)\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/basics/style-customization/_index.en.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Style customization\nweight: 25\n---\n\n**Hugo-theme-learn** has been built to be as configurable as possible by defining multiple [partials](https://gohugo.io/templates/partials/)\n\nIn `themes/hugo-theme-learn/layouts/partials/`, you will find all the partials defined for this theme. If you need to overwrite something, don't change the code directly. Instead [follow this page](https://gohugo.io/themes/customizing/). You'd create a new partial in the `layouts/partials` folder of your local project. This partial will have the priority.\n\nThis theme defines the following partials :\n\n- *header*: the header of the content page (contains the breadcrumbs). _Not meant to be overwritten_\n- *custom-header*: custom headers in page. Meant to be overwritten when adding CSS imports. Don't forget to include `style` HTML tag directive in your file\n- *footer*: the footer of the content page (contains the arrows). _Not meant to be overwritten_\n- *custom-footer*:  custom footer in page. Meant to be overwritten when adding Javacript. Don't forget to include `javascript` HTML tag directive in your file\n- *favicon*: the favicon\n- *logo*: the logo, on top left hand corner.\n- *meta*: HTML meta tags, if you want to change default behavior\n- *menu*: left menu. _Not meant to be overwritten_\n- *menu-footer*: footer of the the left menu\n- *search*: search box\n- *toc*: table of contents\n\n## Change the logo\n\nCreate a new file in `layouts/partials/` named `logo.html`. Then write any HTML you want.\nYou could use an `img` HTML tag and reference an image created under the *static* folder, or you could paste a SVG definition !\n\n{{% notice note %}}\nThe size of the logo will adapt automatically\n{{% /notice %}}\n\n## Change the favicon\n\nIf your favicon is a png, just drop off your image in your local `static/images/` folder and names it `favicon.png`\n\nIf you need to change this default behavior, create a new file in `layouts/partials/` named `favicon.html`. Then write something like this:\n\n```html\n<link rel=\"shortcut icon\" href=\"/images/favicon.png\" type=\"image/x-icon\" />\n```\n\n## Change default colors {#theme-variant}\n\n**Hugo Learn theme** let you choose between 3 native color scheme variants, but feel free to add one yourself ! Default color scheme is based on [Grav Learn Theme](https://learn.getgrav.org/).\n\n### Red variant\n\n```toml\n[params]\n  # Change default color scheme with a variant one. Can be \"red\", \"blue\", \"green\".\n  themeVariant = \"red\"\n```\n\n![Red variant](/basics/style-customization/images/red-variant.png?width=60pc)\n\n### Blue variant\n\n```toml\n[params]\n  # Change default color scheme with a variant one. Can be \"red\", \"blue\", \"green\".\n  themeVariant = \"blue\"\n```\n\n![Blue variant](/basics/style-customization/images/blue-variant.png?width=60pc)\n\n### Green variant\n\n```toml\n[params]\n  # Change default color scheme with a variant one. Can be \"red\", \"blue\", \"green\".\n  themeVariant = \"green\"\n```\n\n![Green variant](/basics/style-customization/images/green-variant.png?width=60pc)\n\n### 'Yours‘ variant\n\nFirst, create a new CSS file in your local `static/css` folder prefixed by `theme` (e.g. with _mine_ theme `static/css/theme-mine.css`). Copy the following content and modify colors in CSS variables.\n\n```css\n\n:root{\n    \n    --MAIN-TEXT-color:#323232; /* Color of text by default */\n    --MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */\n    --MAIN-LINK-color:#1C90F3; /* Color of links */\n    --MAIN-LINK-HOVER-color:#167ad0; /* Color of hovered links */\n    --MAIN-ANCHOR-color: #1C90F3; /* color of anchors on titles */\n\n    --MENU-HEADER-BG-color:#1C90F3; /* Background color of menu header */\n    --MENU-HEADER-BORDER-color:#33a1ff; /*Color of menu header border */ \n\n    --MENU-SEARCH-BG-color:#167ad0; /* Search field background color (by default borders + icons) */\n    --MENU-SEARCH-BOX-color: #33a1ff; /* Override search field border color */\n    --MENU-SEARCH-BOX-ICONS-color: #a1d2fd; /* Override search field icons color */\n\n    --MENU-SECTIONS-ACTIVE-BG-color:#20272b; /* Background color of the active section and its childs */\n    --MENU-SECTIONS-BG-color:#252c31; /* Background color of other sections */\n    --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */\n    --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6;  /* Color of links in menu, when hovered */\n    --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */\n    --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */\n\n    --MENU-VISITED-color: #33a1ff; /* Color of 'page visited' icons in menu */\n    --MENU-SECTION-HR-color: #20272b; /* Color of <hr> separator in menu */\n    \n}\n\nbody {\n    color: var(--MAIN-TEXT-color) !important;\n}\n\ntextarea:focus, input[type=\"email\"]:focus, input[type=\"number\"]:focus, input[type=\"password\"]:focus, input[type=\"search\"]:focus, input[type=\"tel\"]:focus, input[type=\"text\"]:focus, input[type=\"url\"]:focus, input[type=\"color\"]:focus, input[type=\"date\"]:focus, input[type=\"datetime\"]:focus, input[type=\"datetime-local\"]:focus, input[type=\"month\"]:focus, input[type=\"time\"]:focus, input[type=\"week\"]:focus, select[multiple=multiple]:focus {\n    border-color: none;\n    box-shadow: none;\n}\n\nh2, h3, h4, h5 {\n    color: var(--MAIN-TITLES-TEXT-color) !important;\n}\n\na {\n    color: var(--MAIN-LINK-color);\n}\n\n.anchor {\n    color: var(--MAIN-ANCHOR-color);\n}\n\na:hover {\n    color: var(--MAIN-LINK-HOVER-color);\n}\n\n#sidebar ul li.visited > a .read-icon {\n\tcolor: var(--MENU-VISITED-color);\n}\n\n#body a.highlight:after {\n    display: block;\n    content: \"\";\n    height: 1px;\n    width: 0%;\n    -webkit-transition: width 0.5s ease;\n    -moz-transition: width 0.5s ease;\n    -ms-transition: width 0.5s ease;\n    transition: width 0.5s ease;\n    background-color: var(--MAIN-LINK-HOVER-color);\n}\n#sidebar {\n\tbackground-color: var(--MENU-SECTIONS-BG-color);\n}\n#sidebar #header-wrapper {\n    background: var(--MENU-HEADER-BG-color);\n    color: var(--MENU-SEARCH-BOX-color);\n    border-color: var(--MENU-HEADER-BORDER-color);\n}\n#sidebar .searchbox {\n\tborder-color: var(--MENU-SEARCH-BOX-color);\n    background: var(--MENU-SEARCH-BG-color);\n}\n#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {\n    background: var(--MENU-SECTIONS-ACTIVE-BG-color);\n}\n#sidebar .searchbox * {\n    color: var(--MENU-SEARCH-BOX-ICONS-color);\n}\n\n#sidebar a {\n    color: var(--MENU-SECTIONS-LINK-color);\n}\n\n#sidebar a:hover {\n    color: var(--MENU-SECTIONS-LINK-HOVER-color);\n}\n\n#sidebar ul li.active > a {\n    background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);\n    color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;\n}\n\n#sidebar hr {\n    border-color: var(--MENU-SECTION-HR-color);\n}\n```\n\nThen, set the `themeVariant` value with the name of your custom theme file. That's it !\n\n```toml\n[params]\n  # Change default color scheme with a variant one. Can be \"red\", \"blue\", \"green\".\n  themeVariant = \"mine\"\n```\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/basics/style-customization/_index.fr.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Personnalisation du style\nweight: 25\n---\n\n**Hugo-theme-learn** a été conçu pour être aussi configurable que possible en définissant plusieurs [partials](https://gohugo.io/templates/partials/)\n\nDans `themes/hugo-theme-learn/layouts/partials/`, vous pourrez trouver tous les *partials* définis pour ce thème. Si vous avez besoin d'écraser quelque chose, ne modifiez pas le code directement. A la place, [suivez cette page](https://gohugo.io/themes/customizing/). Vous créerez alors un nouveau *partial* dans le dossier `layouts/partials` de votre site local. Ce *partial* aura la priorité.\n\nCe thème définit les *partials* suivant :\n\n- *header*: l'en-tête de la page page (contient le fil d'Ariane). _Pas voué à être écrasé_\n- *custom-header*: En-tête personnalisé. Voué à être écrasé quand vous ajoutez des imports CSS. N'oubliez pas d'inclure la balise HTML `style` dans votre fichier\n- *footer*: le pied-de-page de la page (contains les flèches). _Pas voué à être écrasé_\n- *custom-footer*:  Pied-de-page personnalisé. Voué à être écrasé quand vous ajoutez du Javascript. N'oubliez pas d'inclure la balise HTML `javascript` dans votre fichier\n- *favicon*: le favicon\n- *logo*: le logo, affiché un haut à gauche.\n- *meta*: les balises HTML meta, que vous pouvez écraser sans problème.\n- *menu*: Le menu à gauche. _Pas voué à être écrasé_\n- *menu-footer*: Le pied-de-page du menu\n- *search*: le champ de recherche\n- *toc*: le sommaire\n\n## Changer le logo\n\nCréez un nouveau fichier dans `layouts/partials/`, nommé `logo.html`. Puis, écrivez le code HTML voulu.\nVous pourriez utiliser une balise HTML `img` et référencer une image créée dans le dossier *static*, voire même y coller un cod SVG !\n\n{{% notice note %}}\nLa taille du logo va s'adapter automatiquement\n{{% /notice %}}\n\n## Changer le favicon\n\nSi votre favicon est un png, déposez votre image dans votre dossier local `static/images/` et nommez le `favicon.png`\n\nSi vous avez besoin de changer ce comportement par défaut, créer un nouveau fichier dans `layouts/partials/` et nommez le `favicon.html`. Puis ajoutez quelque chose comme:\n\n```html\n<link rel=\"shortcut icon\" href=\"/images/favicon.png\" type=\"image/x-icon\" />\n```\n\n## Changer les couleurs par défaut {#theme-variant}\n\n**Hugo Learn theme** vous permet de choisir nativement entre 3 schéma de couleurs, mais n'hésitez pas à en ajouter d'autres ! Les couleurs par défaut sont celles de [Grav Learn Theme](https://learn.getgrav.org/).\n\n### Variante rouge\n\n```toml\n[params]\n  # Modifier le schéma de couleur par défaut. Peut être \"red\", \"blue\", \"green\".\n  themeVariant = \"red\"\n```\n\n![Variante rouge](/basics/style-customization/images/red-variant.png?width=60pc)\n\n### Variante bleue\n\n```toml\n[params]\n  # Modifier le schéma de couleur par défaut. Peut être \"red\", \"blue\", \"green\".\n  themeVariant = \"blue\"\n```\n\n![Variante bleue](/basics/style-customization/images/blue-variant.png?width=60pc)\n\n### Variante verte\n\n```toml\n[params]\n  # Modifier le schéma de couleur par défaut. Peut être \"red\", \"blue\", \"green\".\n  themeVariant = \"green\"\n```\n\n![Variante verte](/basics/style-customization/images/green-variant.png?width=60pc)\n\n### Votre variante\n\nPremièrement, créez un nouveau fichier CSS dans votre dossier `static/css`, préfixé par `theme` (ex: avec le theme_lemien_ `static/css/theme-lemien.css`). Copiez le contenu suivant et modifiez les couleurs dans les variables CSS.\n\n```css\n\n:root{\n    \n    --MAIN-TEXT-color:#323232; /* Color of text by default */\n    --MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */\n    --MAIN-LINK-color:#1C90F3; /* Color of links */\n    --MAIN-LINK-HOVER-color:#167ad0; /* Color of hovered links */\n    --MAIN-ANCHOR-color: #1C90F3; /* color of anchors on titles */\n\n    --MENU-HEADER-BG-color:#1C90F3; /* Background color of menu header */\n    --MENU-HEADER-BORDER-color:#33a1ff; /*Color of menu header border */ \n\n    --MENU-SEARCH-BG-color:#167ad0; /* Search field background color (by default borders + icons) */\n    --MENU-SEARCH-BOX-color: #33a1ff; /* Override search field border color */\n    --MENU-SEARCH-BOX-ICONS-color: #a1d2fd; /* Override search field icons color */\n\n    --MENU-SECTIONS-ACTIVE-BG-color:#20272b; /* Background color of the active section and its childs */\n    --MENU-SECTIONS-BG-color:#252c31; /* Background color of other sections */\n    --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */\n    --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6;  /* Color of links in menu, when hovered */\n    --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */\n    --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */\n\n    --MENU-VISITED-color: #33a1ff; /* Color of 'page visited' icons in menu */\n    --MENU-SECTION-HR-color: #20272b; /* Color of <hr> separator in menu */\n    \n}\n\nbody {\n    color: var(--MAIN-TEXT-color) !important;\n}\n\ntextarea:focus, input[type=\"email\"]:focus, input[type=\"number\"]:focus, input[type=\"password\"]:focus, input[type=\"search\"]:focus, input[type=\"tel\"]:focus, input[type=\"text\"]:focus, input[type=\"url\"]:focus, input[type=\"color\"]:focus, input[type=\"date\"]:focus, input[type=\"datetime\"]:focus, input[type=\"datetime-local\"]:focus, input[type=\"month\"]:focus, input[type=\"time\"]:focus, input[type=\"week\"]:focus, select[multiple=multiple]:focus {\n    border-color: none;\n    box-shadow: none;\n}\n\nh2, h3, h4, h5 {\n    color: var(--MAIN-TITLES-TEXT-color) !important;\n}\n\na {\n    color: var(--MAIN-LINK-color);\n}\n\n.anchor {\n    color: var(--MAIN-ANCHOR-color);\n}\n\na:hover {\n    color: var(--MAIN-LINK-HOVER-color);\n}\n\n#sidebar ul li.visited > a .read-icon {\n\tcolor: var(--MENU-VISITED-color);\n}\n\n#body a.highlight:after {\n    display: block;\n    content: \"\";\n    height: 1px;\n    width: 0%;\n    -webkit-transition: width 0.5s ease;\n    -moz-transition: width 0.5s ease;\n    -ms-transition: width 0.5s ease;\n    transition: width 0.5s ease;\n    background-color: var(--MAIN-LINK-HOVER-color);\n}\n#sidebar {\n\tbackground-color: var(--MENU-SECTIONS-BG-color);\n}\n#sidebar #header-wrapper {\n    background: var(--MENU-HEADER-BG-color);\n    color: var(--MENU-SEARCH-BOX-color);\n    border-color: var(--MENU-HEADER-BORDER-color);\n}\n#sidebar .searchbox {\n\tborder-color: var(--MENU-SEARCH-BOX-color);\n    background: var(--MENU-SEARCH-BG-color);\n}\n#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {\n    background: var(--MENU-SECTIONS-ACTIVE-BG-color);\n}\n#sidebar .searchbox * {\n    color: var(--MENU-SEARCH-BOX-ICONS-color);\n}\n\n#sidebar a {\n    color: var(--MENU-SECTIONS-LINK-color);\n}\n\n#sidebar a:hover {\n    color: var(--MENU-SECTIONS-LINK-HOVER-color);\n}\n\n#sidebar ul li.active > a {\n    background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);\n    color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;\n}\n\n#sidebar hr {\n    border-color: var(--MENU-SECTION-HR-color);\n}\n```\n\nPuis, configurez le paramètre `themeVariant` avec le nom de votre variante. C'est tout !\n\n```toml\n[params]\n  # Modifier le schéma de couleur par défaut. Peut être \"red\", \"blue\", \"green\".\n  themeVariant = \"lemien\"\n```\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/_index.en.md",
    "content": "---\ntitle: Content\nweight: 10\nchapter: true\npre: \"<b>2. </b>\"\n---\n\n### Chapter 2\n\n# Content\n\nFind out how to create and organize your content quickly and intuitively.\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/_index.fr.md",
    "content": "---\ntitle: Contenu\nweight: 10\nchapter: true\npre: \"<b>2. </b>\"\n---\n\n### Chapitre 2\n\n# Contenu\n\nDécouvrez comment créer et organiser votre contenu facilement et intuitivement.\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/archetypes.en.md",
    "content": "---\ntitle: Archetypes\nweight: 10\n---\n\nUsing the command: `hugo new [relative new content path]`, you can start a content file with the date and title automatically set. While this is a welcome feature, active writers need more : [archetypes](https://gohugo.io/content/archetypes/).\n\nIt is pre-configured skeleton pages with default front matter. Please refer to the documentation for types of page to understand the differences.\n\n## Chapter {#archetypes-chapter}\n\nTo create a Chapter page, run the following commands\n\n```\nhugo new --kind chapter <name>/_index.md\n```\n\nIt will create a page with predefined Front-Matter:\n\n```markdown\n+++\ntitle = \"{{ replace .TranslationBaseName \"-\" \" \" | title }}\"\ndate = {{ .Date }}\nweight = 5\nchapter = true\npre = \"<b>X. </b>\"\n+++\n\n### Chapter X\n\n# Some Chapter title\n\nLorem Ipsum.\n```\n\n## Default\n\nTo create a default page, run either one of the following commands\n\n```\n# Either\nhugo new <chapter>/<name>/_index.md\n# Or\nhugo new <chapter>/<name>.md\n```\n\nIt will create a page with predefined Front-Matter:\n\n```markdown\n+++\ntitle = \"{{ replace .TranslationBaseName \"-\" \" \" | title }}\"\ndate =  {{ .Date }}\nweight = 5\n+++\n\nLorem Ipsum.\n```"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/archetypes.fr.md",
    "content": "---\ntitle: Archétypes\nweight: 10\n---\n\nEn utilisant la commande: `hugo new [chemin vers nouveau contenu]`, vous pouvez créer un nouveau fichier avec la date et le title automatiquement initialisé. Même si c'est une fonctionnalité intéressante, elle reste limitée pour les auteurs actifs qui ont besoin de mieux : les [archetypes](https://gohugo.io/content/archetypes/).\n\nLes archétypes sont des squelettes de pages préconfigurées avec un Front Matter par défaut. Merci de vous référer à la documentation pour connaitre les différents types de page.\n\n## Chapitre {#archetypes-chapter}\n\nPour créer un chapitre, lancez les commandes suivantes\n\n```\nhugo new --kind chapter <name>/_index.md\n```\n\nCela crééra une page avec le Front Matter suivant:\n\n```markdown\n+++\ntitle = \"{{ replace .TranslationBaseName \"-\" \" \" | title }}\"\ndate = {{ .Date }}\nweight = 5\nchapter = true\npre = \"<b>X. </b>\"\n+++\n\n### Chapter X\n\n# Some Chapter title\n\nLorem Ipsum.\n```\n\n## Défaut\n\nPour créer une page classique, lancer l'une des deux commandes suivantes\n\n```\n# Soit\nhugo new <chapter>/<name>/_index.md\n# Ou\nhugo new <chapter>/<name>.md\n```\n\nCela crééra une page avec le Front Matter suivant:\n\n```markdown\n+++\ntitle = \"{{ replace .TranslationBaseName \"-\" \" \" | title }}\"\ndate =  {{ .Date }}\nweight = 5\n+++\n\nLorem Ipsum.\n```"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/i18n/_index.en.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Multilingual and i18n\nweight: 30\n---\n\n**Learn theme** is fully compatible with Hugo multilingual mode.\n\nIt provides:\n\n- Translation strings for default values (English and French). Feel free to contribute !\n- Automatic menu generation from multilingual content\n- In-browser language switching\n\n![I18n menu](/cont/i18n/images/i18n-menu.gif)\n\n## Basic configuration\n\nAfter learning [how Hugo handle multilingual websites](https://gohugo.io/content-management/multilingual), define your languages in your `config.toml` file.\n\nFor example with current French and English website.\n\n```toml\n# English is the default language\ndefaultContentLanguage = \"en\"\n# Force to have /en/my-page and /fr/my-page routes, even for default language.\ndefaultContentLanguageInSubdir= true\n\n[Languages]\n[Languages.en]\ntitle = \"Documentation for Hugo Learn Theme\"\nweight = 1\nlanguageName = \"English\"\n\n[Languages.fr]\ntitle = \"Documentation du thème Hugo Learn\"\nweight = 2\nlanguageName = \"Français\"\n```\n\nThen, for each new page, append the *id* of the language to the file.\n\n- Single file `my-page.md` is split in two files:\n    - in English: `my-page.en.md`\n    - in French: `my-page.fr.md`\n- Single file `_index.md` is split in two files:\n    - in English: `_index.en.md`\n    - in French: `_index.fr.md`\n\n{{% notice info %}}\nBe aware that only translated pages are displayed in menu. It's not replaced with default language content.\n{{% /notice %}}\n\n{{% notice tip %}}\nUse [slug](https://gohugo.io/content-management/multilingual/#translate-your-content) Front Matter parameter to translate urls too.\n{{% /notice %}}\n\n## Overwrite translation strings\n\nTranslations strings are used for common default values used in the theme (*Edit this page* button, *Search placeholder* and so on). Translations are available in french and english but you may use another language or want to override default values.\n\nTo override these values, create a new file in your local i18n folder `i18n/<idlanguage>.toml` and inspire yourself from the theme `themes/hugo-theme-learn/i18n/en.toml` \n\nBy the way, as these translations could be used by other people, please take the time to propose a translation by [making a PR](https://github.com/matcornic/hugo-theme-learn/pulls) to the theme ! \n\n## Disable language switching\n\nSwitching the language in the browser is a great feature, but for some reasons you may want to disable it. \n\nJust set `disableLanguageSwitchingButton=true` in your `config.toml`\n\n```toml\n[params]\n  # When using mulitlingual website, disable the switch language button.\n  disableLanguageSwitchingButton = true\n```\n\n![I18n menu](/cont/i18n/images/i18n-menu.gif)"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/i18n/_index.fr.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Multi-langue et i18n\nweight: 30\n---\n\n**Learn** est complètement compatible avec le mode multi-langue d'Hugo.\n\nIl fournit :\n\n- Des *translation strings* pour les valeurs par défaut utilisées par le thème (Anglais et Français). N'hésitez pas à contribuer !\n- Génération automatique du menu avec le contenu multi-langue\n- Modification de la langue dans le navigateur\n\n![I18n menu](/cont/i18n/images/i18n-menu.gif)\n\n## Configuration simple\n\nAprès avoir appris [comment Hugo gère les sites multi-langue](https://gohugo.io/content-management/multilingual), définissez vos langues dans votre fichier `config.toml`.\n\nPar exemple, pour ce site, avec du contenu en français et en anglais.\n\n```toml\n# Anglais est la langue par défaut\ndefaultContentLanguage = \"en\"\n# Force d'avoir /en/ma-page et /fr/ma-page routes, même avec la langue par défaut.\ndefaultContentLanguageInSubdir= true\n\n[Languages]\n[Languages.en]\ntitle = \"Documentation for Hugo Learn Theme\"\nweight = 1\nlanguageName = \"English\"\n\n[Languages.fr]\ntitle = \"Documentation du thème Hugo Learn\"\nweight = 2\nlanguageName = \"Français\"\n```\n\nPuis, pour chaque nouvelle page, ajoutez *l'id* de la langue du fichier.\n\n- Le fichier `my-page.md` est découpé en deux fichiers :\n    - en anglais : `my-page.en.md`\n    - en français : `my-page.fr.md`\n- Le fichier `_index.md` est découpé en deux fichiers :\n    - en anglais: `_index.en.md`\n    - en français: `_index.fr.md`\n\n{{% notice info %}}\nAttention, seulement les pages traduites sont affichées dans le menu. Le contenu n'est pas remplacé par les pages de la langue par défaut.\n{{% /notice %}}\n\n{{% notice tip %}}\nUtilisez le paramètre du Front Matter [slug](https://gohugo.io/content-management/multilingual/#translate-your-content) pour traduire également les URLs.\n{{% /notice %}}\n\n## Surcharger les *translation strings*\n\nLes *Translations strings* sont utilisées comme valeurs par défaut dans le thème (Bouton *Modifier la page*, Element de subsitution *Recherche*, etc.). Les traductions sont disponibles en français et en anglais mais vous pouvez utiliser n'importe quelle autre langue et surcharger avec vos propres valeurs.\n\nPour surcharger ces valeurs, créer un nouveau fichier dans votre dossier i18n local `i18n/<idlanguage>.toml` et inspirez vous du thème `themes/hugo-theme-learn/i18n/en.toml` \n\nD'ailleurs, ces traductions pour servir à tout le monde, donc svp prenez le temps de [proposer une Pull Request](https://github.com/matcornic/hugo-theme-learn/pulls) ! \n\n## Désactiver le changement de langue\n\nVous pouvez changer de langue directement dans le navigateur. C'est une super fonctionnalité, mais vous avez peut-être besoin de la désactiver. \n\nPour ce faire, ajouter le paramètre `disableLanguageSwitchingButton=true` dans votre `config.toml`\n\n```toml\n[params]\n  # Quand vous utilisez un site en multi-langue, désactive le bouton de changment de langue.\n  disableLanguageSwitchingButton = true\n```\n\n![I18n menu](/cont/i18n/images/i18n-menu.gif)"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/markdown.en.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Markdown syntax\nweight: 15\n---\n\n{{% notice note %}}\nThis page is a shameful copy of the great [Grav original page](http://learn.getgrav.org/content/markdown).\nOnly difference is information about image customization ([resizing]({{< relref \"#resizing-image\" >}}), [add CSS classes]({{< relref \"#add-css-classes\" >}})...)\n{{% /notice%}}\n\nLet's face it: Writing content for the Web is tiresome. WYSIWYG editors help alleviate this task, but they generally result in horrible code, or worse yet, ugly web pages.\n\n**Markdown** is a better way to write **HTML**, without all the complexities and ugliness that usually accompanies it.\n\nSome of the key benefits are:\n\n1. Markdown is simple to learn, with minimal extra characters so it's also quicker to write content.\n2. Less chance of errors when writing in markdown.\n3. Produces valid XHTML output.\n4. Keeps the content and the visual display separate, so you cannot mess up the look of your site.\n5. Write in any text editor or Markdown application you like.\n6. Markdown is a joy to use!\n\nJohn Gruber, the author of Markdown, puts it like this:\n\n> The overriding design goal for Markdown’s formatting syntax is to make it as readable as possible. The idea is that a Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions. While Markdown’s syntax has been influenced by several existing text-to-HTML filters, the single biggest source of inspiration for Markdown’s syntax is the format of plain text email.\n> -- <cite>John Gruber</cite>\n\n\nGrav ships with built-in support for [Markdown](http://daringfireball.net/projects/markdown/) and [Markdown Extra](https://michelf.ca/projects/php-markdown/extra/). You must enable **Markdown Extra** in your `system.yaml` configuration file\n\nWithout further delay, let us go over the main elements of Markdown and what the resulting HTML looks like:\n\n{{% notice info %}}\n<i class=\"fa fa-bookmark\"></i> Bookmark this page for easy future reference!\n{{% /notice %}}\n\n## Headings\n\nHeadings from `h1` through `h6` are constructed with a `#` for each level:\n\n```markdown\n# h1 Heading\n## h2 Heading\n### h3 Heading\n#### h4 Heading\n##### h5 Heading\n###### h6 Heading\n```\n\nRenders to:\n\n# h1 Heading\n## h2 Heading\n### h3 Heading\n#### h4 Heading\n##### h5 Heading\n###### h6 Heading\n\nHTML:\n\n```html\n<h1>h1 Heading</h1>\n<h2>h2 Heading</h2>\n<h3>h3 Heading</h3>\n<h4>h4 Heading</h4>\n<h5>h5 Heading</h5>\n<h6>h6 Heading</h6>\n```\n\n## Comments\n\nComments should be HTML compatible\n\n```html\n<!--\nThis is a comment\n-->\n```\nComment below should **NOT** be seen:\n\n<!--\nThis is a comment\n-->\n\n\n## Horizontal Rules\n\nThe HTML `<hr>` element is for creating a \"thematic break\" between paragraph-level elements. In markdown, you can create a `<hr>` with any of the following:\n\n* `___`: three consecutive underscores\n* `---`: three consecutive dashes\n* `***`: three consecutive asterisks\n\nrenders to:\n\n___\n\n---\n\n***\n\n\n## Body Copy\n\nBody copy written as normal, plain text will be wrapped with `<p></p>` tags in the rendered HTML.\n\nSo this body copy:\n\n```markdown\nLorem ipsum dolor sit amet, graecis denique ei vel, at duo primis mandamus. Et legere ocurreret pri, animal tacimates complectitur ad cum. Cu eum inermis inimicus efficiendi. Labore officiis his ex, soluta officiis concludaturque ei qui, vide sensibus vim ad.\n```\nrenders to this HTML:\n\n```html\n<p>Lorem ipsum dolor sit amet, graecis denique ei vel, at duo primis mandamus. Et legere ocurreret pri, animal tacimates complectitur ad cum. Cu eum inermis inimicus efficiendi. Labore officiis his ex, soluta officiis concludaturque ei qui, vide sensibus vim ad.</p>\n```\n\n## Emphasis\n\n### Bold\nFor emphasizing a snippet of text with a heavier font-weight.\n\nThe following snippet of text is **rendered as bold text**.\n\n```markdown\n**rendered as bold text**\n```\nrenders to:\n\n**rendered as bold text**\n\nand this HTML\n\n```html\n<strong>rendered as bold text</strong>\n```\n\n### Italics\nFor emphasizing a snippet of text with italics.\n\nThe following snippet of text is _rendered as italicized text_.\n\n```markdown\n_rendered as italicized text_\n```\n\nrenders to:\n\n_rendered as italicized text_\n\nand this HTML:\n\n```html\n<em>rendered as italicized text</em>\n```\n\n\n### strikethrough\nIn GFM (GitHub flavored Markdown) you can do strikethroughs.\n\n```markdown\n~~Strike through this text.~~\n```\nWhich renders to:\n\n~~Strike through this text.~~\n\nHTML:\n\n```html\n<del>Strike through this text.</del>\n```\n\n## Blockquotes\nFor quoting blocks of content from another source within your document.\n\nAdd `>` before any text you want to quote.\n\n```markdown\n> **Fusion Drive** combines a hard drive with a flash storage (solid-state drive) and presents it as a single logical volume with the space of both drives combined.\n```\n\nRenders to:\n\n> **Fusion Drive** combines a hard drive with a flash storage (solid-state drive) and presents it as a single logical volume with the space of both drives combined.\n\nand this HTML:\n\n```html\n<blockquote>\n  <p><strong>Fusion Drive</strong> combines a hard drive with a flash storage (solid-state drive) and presents it as a single logical volume with the space of both drives combined.</p>\n</blockquote>\n```\n\nBlockquotes can also be nested:\n\n```markdown\n> Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.\nNunc augue augue, aliquam non hendrerit ac, commodo vel nisi.\n>> Sed adipiscing elit vitae augue consectetur a gravida nunc vehicula. Donec auctor\nodio non est accumsan facilisis. Aliquam id turpis in dolor tincidunt mollis ac eu diam.\n```\n\nRenders to:\n\n> Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.\nNunc augue augue, aliquam non hendrerit ac, commodo vel nisi.\n>> Sed adipiscing elit vitae augue consectetur a gravida nunc vehicula. Donec auctor\nodio non est accumsan facilisis. Aliquam id turpis in dolor tincidunt mollis ac eu diam.\n\n\n## Notices\n\n{{% notice note %}}\nThe old mechanism for notices overriding the block quote syntax (`>>>`) has been deprecated.  Notices are now handled via a dedicated plugin called [Markdown Notices](https://github.com/getgrav/grav-plugin-markdown-notices)\n{{% /notice %}}\n\n\n## Lists\n\n### Unordered\nA list of items in which the order of the items does not explicitly matter.\n\nYou may use any of the following symbols to denote bullets for each list item:\n\n```markdown\n* valid bullet\n- valid bullet\n+ valid bullet\n```\n\nFor example\n\n```markdown\n+ Lorem ipsum dolor sit amet\n+ Consectetur adipiscing elit\n+ Integer molestie lorem at massa\n+ Facilisis in pretium nisl aliquet\n+ Nulla volutpat aliquam velit\n  - Phasellus iaculis neque\n  - Purus sodales ultricies\n  - Vestibulum laoreet porttitor sem\n  - Ac tristique libero volutpat at\n+ Faucibus porta lacus fringilla vel\n+ Aenean sit amet erat nunc\n+ Eget porttitor lorem\n```\nRenders to:\n\n+ Lorem ipsum dolor sit amet\n+ Consectetur adipiscing elit\n+ Integer molestie lorem at massa\n+ Facilisis in pretium nisl aliquet\n+ Nulla volutpat aliquam velit\n  - Phasellus iaculis neque\n  - Purus sodales ultricies\n  - Vestibulum laoreet porttitor sem\n  - Ac tristique libero volutpat at\n+ Faucibus porta lacus fringilla vel\n+ Aenean sit amet erat nunc\n+ Eget porttitor lorem\n\nAnd this HTML\n\n```html\n<ul>\n  <li>Lorem ipsum dolor sit amet</li>\n  <li>Consectetur adipiscing elit</li>\n  <li>Integer molestie lorem at massa</li>\n  <li>Facilisis in pretium nisl aliquet</li>\n  <li>Nulla volutpat aliquam velit\n    <ul>\n      <li>Phasellus iaculis neque</li>\n      <li>Purus sodales ultricies</li>\n      <li>Vestibulum laoreet porttitor sem</li>\n      <li>Ac tristique libero volutpat at</li>\n    </ul>\n  </li>\n  <li>Faucibus porta lacus fringilla vel</li>\n  <li>Aenean sit amet erat nunc</li>\n  <li>Eget porttitor lorem</li>\n</ul>\n```\n\n### Ordered\n\nA list of items in which the order of items does explicitly matter.\n\n```markdown\n1. Lorem ipsum dolor sit amet\n2. Consectetur adipiscing elit\n3. Integer molestie lorem at massa\n4. Facilisis in pretium nisl aliquet\n5. Nulla volutpat aliquam velit\n6. Faucibus porta lacus fringilla vel\n7. Aenean sit amet erat nunc\n8. Eget porttitor lorem\n```\nRenders to:\n\n1. Lorem ipsum dolor sit amet\n2. Consectetur adipiscing elit\n3. Integer molestie lorem at massa\n4. Facilisis in pretium nisl aliquet\n5. Nulla volutpat aliquam velit\n6. Faucibus porta lacus fringilla vel\n7. Aenean sit amet erat nunc\n8. Eget porttitor lorem\n\nAnd this HTML:\n\n```html\n<ol>\n  <li>Lorem ipsum dolor sit amet</li>\n  <li>Consectetur adipiscing elit</li>\n  <li>Integer molestie lorem at massa</li>\n  <li>Facilisis in pretium nisl aliquet</li>\n  <li>Nulla volutpat aliquam velit</li>\n  <li>Faucibus porta lacus fringilla vel</li>\n  <li>Aenean sit amet erat nunc</li>\n  <li>Eget porttitor lorem</li>\n</ol>\n```\n\n**TIP**: If you just use `1.` for each number, Markdown will automatically number each item. For example:\n\n```markdown\n1. Lorem ipsum dolor sit amet\n1. Consectetur adipiscing elit\n1. Integer molestie lorem at massa\n1. Facilisis in pretium nisl aliquet\n1. Nulla volutpat aliquam velit\n1. Faucibus porta lacus fringilla vel\n1. Aenean sit amet erat nunc\n1. Eget porttitor lorem\n```\n\nRenders to:\n\n1. Lorem ipsum dolor sit amet\n2. Consectetur adipiscing elit\n3. Integer molestie lorem at massa\n4. Facilisis in pretium nisl aliquet\n5. Nulla volutpat aliquam velit\n6. Faucibus porta lacus fringilla vel\n7. Aenean sit amet erat nunc\n8. Eget porttitor lorem\n\n## Code\n\n### Inline code\nWrap inline snippets of code with `` ` ``.\n\n```markdown\nIn this example, `<section></section>` should be wrapped as **code**.\n```\n\nRenders to:\n\nIn this example, `<section></section>` should be wrapped with **code**.\n\nHTML:\n\n```html\n<p>In this example, <code>&lt;section&gt;&lt;/section&gt;</code> should be wrapped with <strong>code</strong>.</p>\n```\n\n### Indented code\n\nOr indent several lines of code by at least four spaces, as in:\n\n<pre>\n  // Some comments\n  line 1 of code\n  line 2 of code\n  line 3 of code\n</pre>\n\nRenders to:\n\n    // Some comments\n    line 1 of code\n    line 2 of code\n    line 3 of code\n\nHTML:\n\n```html\n<pre>\n  <code>\n    // Some comments\n    line 1 of code\n    line 2 of code\n    line 3 of code\n  </code>\n</pre>\n```\n\n\n### Block code \"fences\"\n\nUse \"fences\"  ```` ``` ```` to block in multiple lines of code.\n\n<pre>\n``` markup\nSample text here...\n```\n</pre>\n\n\n```\nSample text here...\n```\n\nHTML:\n\n```html\n<pre>\n  <code>Sample text here...</code>\n</pre>\n```\n\n### Syntax highlighting\n\nGFM, or \"GitHub Flavored Markdown\" also supports syntax highlighting. To activate it, simply add the file extension of the language you want to use directly after the first code \"fence\", ` ```js `, and syntax highlighting will automatically be applied in the rendered HTML. For example, to apply syntax highlighting to JavaScript code:\n\n<pre>\n```js\ngrunt.initConfig({\n  assemble: {\n    options: {\n      assets: 'docs/assets',\n      data: 'src/data/*.{json,yml}',\n      helpers: 'src/custom-helpers.js',\n      partials: ['src/partials/**/*.{hbs,md}']\n    },\n    pages: {\n      options: {\n        layout: 'default.hbs'\n      },\n      files: {\n        './': ['src/templates/pages/index.hbs']\n      }\n    }\n  }\n};\n```\n</pre>\n\nRenders to:\n\n```js\ngrunt.initConfig({\n  assemble: {\n    options: {\n      assets: 'docs/assets',\n      data: 'src/data/*.{json,yml}',\n      helpers: 'src/custom-helpers.js',\n      partials: ['src/partials/**/*.{hbs,md}']\n    },\n    pages: {\n      options: {\n        layout: 'default.hbs'\n      },\n      files: {\n        './': ['src/templates/pages/index.hbs']\n      }\n    }\n  }\n};\n```\n\n## Tables\nTables are created by adding pipes as dividers between each cell, and by adding a line of dashes (also separated by bars) beneath the header. Note that the pipes do not need to be vertically aligned.\n\n\n```markdown\n| Option | Description |\n| ------ | ----------- |\n| data   | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext    | extension to be used for dest files. |\n```\n\nRenders to:\n\n| Option | Description |\n| ------ | ----------- |\n| data   | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext    | extension to be used for dest files. |\n\nAnd this HTML:\n\n```html\n<table>\n  <tr>\n    <th>Option</th>\n    <th>Description</th>\n  </tr>\n  <tr>\n    <td>data</td>\n    <td>path to data files to supply the data that will be passed into templates.</td>\n  </tr>\n  <tr>\n    <td>engine</td>\n    <td>engine to be used for processing templates. Handlebars is the default.</td>\n  </tr>\n  <tr>\n    <td>ext</td>\n    <td>extension to be used for dest files.</td>\n  </tr>\n</table>\n```\n\n### Right aligned text\n\nAdding a colon on the right side of the dashes below any heading will right align text for that column.\n\n```markdown\n| Option | Description |\n| ------:| -----------:|\n| data   | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext    | extension to be used for dest files. |\n```\n\n| Option | Description |\n| ------:| -----------:|\n| data   | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext    | extension to be used for dest files. |\n\n## Links\n\n### Basic link\n\n```markdown\n[Assemble](http://assemble.io)\n```\n\nRenders to (hover over the link, there is no tooltip):\n\n[Assemble](http://assemble.io)\n\nHTML:\n\n```html\n<a href=\"http://assemble.io\">Assemble</a>\n```\n\n\n### Add a title\n\n```markdown\n[Upstage](https://github.com/upstage/ \"Visit Upstage!\")\n```\n\nRenders to (hover over the link, there should be a tooltip):\n\n[Upstage](https://github.com/upstage/ \"Visit Upstage!\")\n\nHTML:\n\n```html\n<a href=\"https://github.com/upstage/\" title=\"Visit Upstage!\">Upstage</a>\n```\n\n### Named Anchors\n\nNamed anchors enable you to jump to the specified anchor point on the same page. For example, each of these chapters:\n\n```markdown\n# Table of Contents\n  * [Chapter 1](#chapter-1)\n  * [Chapter 2](#chapter-2)\n  * [Chapter 3](#chapter-3)\n```\nwill jump to these sections:\n\n```markdown\n## Chapter 1 <a id=\"chapter-1\"></a>\nContent for chapter one.\n\n## Chapter 2 <a id=\"chapter-2\"></a>\nContent for chapter one.\n\n## Chapter 3 <a id=\"chapter-3\"></a>\nContent for chapter one.\n```\n**NOTE** that specific placement of the anchor tag seems to be arbitrary. They are placed inline here since it seems to be unobtrusive, and it works.\n\n## Images {#images}\nImages have a similar syntax to links but include a preceding exclamation point.\n\n```markdown\n![Minion](http://octodex.github.com/images/minion.png)\n```\n![Minion](http://octodex.github.com/images/minion.png)\n\nor\n```markdown\n![Alt text](http://octodex.github.com/images/stormtroopocat.jpg \"The Stormtroopocat\")\n```\n![Alt text](http://octodex.github.com/images/stormtroopocat.jpg \"The Stormtroopocat\")\n\nLike links, Images also have a footnote style syntax\n\n### Alternative usage : note images\n\n```markdown\n![Alt text][id]\n```\n![Alt text][id]\n\nWith a reference later in the document defining the URL location:\n\n[id]: http://octodex.github.com/images/dojocat.jpg  \"The Dojocat\"\n\n    [id]: http://octodex.github.com/images/dojocat.jpg  \"The Dojocat\"\n\n### Resizing image\n\nAdd HTTP parameters `width` and/or `height` to the link image to resize the image. Values are CSS values (default is `auto`).\n\n```markdown\n![Minion](http://octodex.github.com/images/minion.png?width=20pc)\n```\n\n![Minion](http://octodex.github.com/images/minion.png?width=20pc)\n\n```markdown\n![Minion](http://octodex.github.com/images/minion.png?height=50px)\n```\n\n![Minion](http://octodex.github.com/images/minion.png?height=50px)\n\n```markdown\n![Minion](http://octodex.github.com/images/minion.png?height=50px&width=300px)\n```\n\n![Minion](http://octodex.github.com/images/minion.png?height=50px&width=300px)\n\n### Add CSS classes\n\nAdd a HTTP `classes` parameter to the link image to add CSS classes. `shadow`and `border` are available but you could define other ones.\n\n```markdown\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?classes=shadow)\n```\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?width=40pc&classes=shadow)\n\n```markdown\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?classes=border)\n```\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?width=40pc&classes=border)\n\n```markdown\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?classes=border,shadow)\n```\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?width=40pc&classes=border,shadow)\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/markdown.fr.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Syntaxe Markdown\nweight: 15\n---\n\n{{% notice note %}}\nCette page est une copie de la [doc de Grav](http://learn.getgrav.org/content/markdown).\nLa seule différence porte sur la personalisation des images ([taille]({{< relref \"#resizing-image\" >}}), [ajout de classes CSS]({{< relref \"#add-css-classes\" >}})...)\nPour des raisons évidentes, cette page n'a pas été traduites en français 😁\n{{% /notice%}}\n\nLet's face it: Writing content for the Web is tiresome. WYSIWYG editors help alleviate this task, but they generally result in horrible code, or worse yet, ugly web pages.\n\n**Markdown** is a better way to write **HTML**, without all the complexities and ugliness that usually accompanies it.\n\nSome of the key benefits are:\n\n1. Markdown is simple to learn, with minimal extra characters so it's also quicker to write content.\n2. Less chance of errors when writing in markdown.\n3. Produces valid XHTML output.\n4. Keeps the content and the visual display separate, so you cannot mess up the look of your site.\n5. Write in any text editor or Markdown application you like.\n6. Markdown is a joy to use!\n\nJohn Gruber, the author of Markdown, puts it like this:\n\n> The overriding design goal for Markdown’s formatting syntax is to make it as readable as possible. The idea is that a Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions. While Markdown’s syntax has been influenced by several existing text-to-HTML filters, the single biggest source of inspiration for Markdown’s syntax is the format of plain text email.\n> -- <cite>John Gruber</cite>\n\n\nGrav ships with built-in support for [Markdown](http://daringfireball.net/projects/markdown/) and [Markdown Extra](https://michelf.ca/projects/php-markdown/extra/). You must enable **Markdown Extra** in your `system.yaml` configuration file\n\nWithout further delay, let us go over the main elements of Markdown and what the resulting HTML looks like:\n\n{{% notice info %}}\n<i class=\"fa fa-bookmark\"></i> Bookmark this page for easy future reference!\n{{% /notice %}}\n\n## Headings\n\nHeadings from `h1` through `h6` are constructed with a `#` for each level:\n\n```markdown\n# h1 Heading\n## h2 Heading\n### h3 Heading\n#### h4 Heading\n##### h5 Heading\n###### h6 Heading\n```\n\nRenders to:\n\n# h1 Heading\n## h2 Heading\n### h3 Heading\n#### h4 Heading\n##### h5 Heading\n###### h6 Heading\n\nHTML:\n\n```html\n<h1>h1 Heading</h1>\n<h2>h2 Heading</h2>\n<h3>h3 Heading</h3>\n<h4>h4 Heading</h4>\n<h5>h5 Heading</h5>\n<h6>h6 Heading</h6>\n```\n\n## Comments\n\nComments should be HTML compatible\n\n```html\n<!--\nThis is a comment\n-->\n```\nComment below should **NOT** be seen:\n\n<!--\nThis is a comment\n-->\n\n\n## Horizontal Rules\n\nThe HTML `<hr>` element is for creating a \"thematic break\" between paragraph-level elements. In markdown, you can create a `<hr>` with any of the following:\n\n* `___`: three consecutive underscores\n* `---`: three consecutive dashes\n* `***`: three consecutive asterisks\n\nrenders to:\n\n___\n\n---\n\n***\n\n\n## Body Copy\n\nBody copy written as normal, plain text will be wrapped with `<p></p>` tags in the rendered HTML.\n\nSo this body copy:\n\n```markdown\nLorem ipsum dolor sit amet, graecis denique ei vel, at duo primis mandamus. Et legere ocurreret pri, animal tacimates complectitur ad cum. Cu eum inermis inimicus efficiendi. Labore officiis his ex, soluta officiis concludaturque ei qui, vide sensibus vim ad.\n```\nrenders to this HTML:\n\n```html\n<p>Lorem ipsum dolor sit amet, graecis denique ei vel, at duo primis mandamus. Et legere ocurreret pri, animal tacimates complectitur ad cum. Cu eum inermis inimicus efficiendi. Labore officiis his ex, soluta officiis concludaturque ei qui, vide sensibus vim ad.</p>\n```\n\n## Emphasis\n\n### Bold\nFor emphasizing a snippet of text with a heavier font-weight.\n\nThe following snippet of text is **rendered as bold text**.\n\n```markdown\n**rendered as bold text**\n```\nrenders to:\n\n**rendered as bold text**\n\nand this HTML\n\n```html\n<strong>rendered as bold text</strong>\n```\n\n### Italics\nFor emphasizing a snippet of text with italics.\n\nThe following snippet of text is _rendered as italicized text_.\n\n```markdown\n_rendered as italicized text_\n```\n\nrenders to:\n\n_rendered as italicized text_\n\nand this HTML:\n\n```html\n<em>rendered as italicized text</em>\n```\n\n\n### strikethrough\nIn GFM (GitHub flavored Markdown) you can do strikethroughs.\n\n```markdown\n~~Strike through this text.~~\n```\nWhich renders to:\n\n~~Strike through this text.~~\n\nHTML:\n\n```html\n<del>Strike through this text.</del>\n```\n\n## Blockquotes\nFor quoting blocks of content from another source within your document.\n\nAdd `>` before any text you want to quote.\n\n```markdown\n> **Fusion Drive** combines a hard drive with a flash storage (solid-state drive) and presents it as a single logical volume with the space of both drives combined.\n```\n\nRenders to:\n\n> **Fusion Drive** combines a hard drive with a flash storage (solid-state drive) and presents it as a single logical volume with the space of both drives combined.\n\nand this HTML:\n\n```html\n<blockquote>\n  <p><strong>Fusion Drive</strong> combines a hard drive with a flash storage (solid-state drive) and presents it as a single logical volume with the space of both drives combined.</p>\n</blockquote>\n```\n\nBlockquotes can also be nested:\n\n```markdown\n> Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.\nNunc augue augue, aliquam non hendrerit ac, commodo vel nisi.\n>> Sed adipiscing elit vitae augue consectetur a gravida nunc vehicula. Donec auctor\nodio non est accumsan facilisis. Aliquam id turpis in dolor tincidunt mollis ac eu diam.\n```\n\nRenders to:\n\n> Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.\nNunc augue augue, aliquam non hendrerit ac, commodo vel nisi.\n>> Sed adipiscing elit vitae augue consectetur a gravida nunc vehicula. Donec auctor\nodio non est accumsan facilisis. Aliquam id turpis in dolor tincidunt mollis ac eu diam.\n\n\n## Notices\n\n{{% notice note %}}\nThe old mechanism for notices overriding the block quote syntax (`>>>`) has been deprecated.  Notices are now handled via a dedicated plugin called [Markdown Notices](https://github.com/getgrav/grav-plugin-markdown-notices)\n{{% /notice %}}\n\n\n## Lists\n\n### Unordered\nA list of items in which the order of the items does not explicitly matter.\n\nYou may use any of the following symbols to denote bullets for each list item:\n\n```markdown\n* valid bullet\n- valid bullet\n+ valid bullet\n```\n\nFor example\n\n```markdown\n+ Lorem ipsum dolor sit amet\n+ Consectetur adipiscing elit\n+ Integer molestie lorem at massa\n+ Facilisis in pretium nisl aliquet\n+ Nulla volutpat aliquam velit\n  - Phasellus iaculis neque\n  - Purus sodales ultricies\n  - Vestibulum laoreet porttitor sem\n  - Ac tristique libero volutpat at\n+ Faucibus porta lacus fringilla vel\n+ Aenean sit amet erat nunc\n+ Eget porttitor lorem\n```\nRenders to:\n\n+ Lorem ipsum dolor sit amet\n+ Consectetur adipiscing elit\n+ Integer molestie lorem at massa\n+ Facilisis in pretium nisl aliquet\n+ Nulla volutpat aliquam velit\n  - Phasellus iaculis neque\n  - Purus sodales ultricies\n  - Vestibulum laoreet porttitor sem\n  - Ac tristique libero volutpat at\n+ Faucibus porta lacus fringilla vel\n+ Aenean sit amet erat nunc\n+ Eget porttitor lorem\n\nAnd this HTML\n\n```html\n<ul>\n  <li>Lorem ipsum dolor sit amet</li>\n  <li>Consectetur adipiscing elit</li>\n  <li>Integer molestie lorem at massa</li>\n  <li>Facilisis in pretium nisl aliquet</li>\n  <li>Nulla volutpat aliquam velit\n    <ul>\n      <li>Phasellus iaculis neque</li>\n      <li>Purus sodales ultricies</li>\n      <li>Vestibulum laoreet porttitor sem</li>\n      <li>Ac tristique libero volutpat at</li>\n    </ul>\n  </li>\n  <li>Faucibus porta lacus fringilla vel</li>\n  <li>Aenean sit amet erat nunc</li>\n  <li>Eget porttitor lorem</li>\n</ul>\n```\n\n### Ordered\n\nA list of items in which the order of items does explicitly matter.\n\n```markdown\n1. Lorem ipsum dolor sit amet\n2. Consectetur adipiscing elit\n3. Integer molestie lorem at massa\n4. Facilisis in pretium nisl aliquet\n5. Nulla volutpat aliquam velit\n6. Faucibus porta lacus fringilla vel\n7. Aenean sit amet erat nunc\n8. Eget porttitor lorem\n```\nRenders to:\n\n1. Lorem ipsum dolor sit amet\n2. Consectetur adipiscing elit\n3. Integer molestie lorem at massa\n4. Facilisis in pretium nisl aliquet\n5. Nulla volutpat aliquam velit\n6. Faucibus porta lacus fringilla vel\n7. Aenean sit amet erat nunc\n8. Eget porttitor lorem\n\nAnd this HTML:\n\n```html\n<ol>\n  <li>Lorem ipsum dolor sit amet</li>\n  <li>Consectetur adipiscing elit</li>\n  <li>Integer molestie lorem at massa</li>\n  <li>Facilisis in pretium nisl aliquet</li>\n  <li>Nulla volutpat aliquam velit</li>\n  <li>Faucibus porta lacus fringilla vel</li>\n  <li>Aenean sit amet erat nunc</li>\n  <li>Eget porttitor lorem</li>\n</ol>\n```\n\n**TIP**: If you just use `1.` for each number, Markdown will automatically number each item. For example:\n\n```markdown\n1. Lorem ipsum dolor sit amet\n1. Consectetur adipiscing elit\n1. Integer molestie lorem at massa\n1. Facilisis in pretium nisl aliquet\n1. Nulla volutpat aliquam velit\n1. Faucibus porta lacus fringilla vel\n1. Aenean sit amet erat nunc\n1. Eget porttitor lorem\n```\n\nRenders to:\n\n1. Lorem ipsum dolor sit amet\n2. Consectetur adipiscing elit\n3. Integer molestie lorem at massa\n4. Facilisis in pretium nisl aliquet\n5. Nulla volutpat aliquam velit\n6. Faucibus porta lacus fringilla vel\n7. Aenean sit amet erat nunc\n8. Eget porttitor lorem\n\n## Code\n\n### Inline code\nWrap inline snippets of code with `` ` ``.\n\n```markdown\nIn this example, `<section></section>` should be wrapped as **code**.\n```\n\nRenders to:\n\nIn this example, `<section></section>` should be wrapped with **code**.\n\nHTML:\n\n```html\n<p>In this example, <code>&lt;section&gt;&lt;/section&gt;</code> should be wrapped with <strong>code</strong>.</p>\n```\n\n### Indented code\n\nOr indent several lines of code by at least four spaces, as in:\n\n<pre>\n  // Some comments\n  line 1 of code\n  line 2 of code\n  line 3 of code\n</pre>\n\nRenders to:\n\n    // Some comments\n    line 1 of code\n    line 2 of code\n    line 3 of code\n\nHTML:\n\n```html\n<pre>\n  <code>\n    // Some comments\n    line 1 of code\n    line 2 of code\n    line 3 of code\n  </code>\n</pre>\n```\n\n\n### Block code \"fences\"\n\nUse \"fences\"  ```` ``` ```` to block in multiple lines of code.\n\n<pre>\n``` markup\nSample text here...\n```\n</pre>\n\n\n```\nSample text here...\n```\n\nHTML:\n\n```html\n<pre>\n  <code>Sample text here...</code>\n</pre>\n```\n\n### Syntax highlighting\n\nGFM, or \"GitHub Flavored Markdown\" also supports syntax highlighting. To activate it, simply add the file extension of the language you want to use directly after the first code \"fence\", ` ```js `, and syntax highlighting will automatically be applied in the rendered HTML. For example, to apply syntax highlighting to JavaScript code:\n\n<pre>\n```js\ngrunt.initConfig({\n  assemble: {\n    options: {\n      assets: 'docs/assets',\n      data: 'src/data/*.{json,yml}',\n      helpers: 'src/custom-helpers.js',\n      partials: ['src/partials/**/*.{hbs,md}']\n    },\n    pages: {\n      options: {\n        layout: 'default.hbs'\n      },\n      files: {\n        './': ['src/templates/pages/index.hbs']\n      }\n    }\n  }\n};\n```\n</pre>\n\nRenders to:\n\n```js\ngrunt.initConfig({\n  assemble: {\n    options: {\n      assets: 'docs/assets',\n      data: 'src/data/*.{json,yml}',\n      helpers: 'src/custom-helpers.js',\n      partials: ['src/partials/**/*.{hbs,md}']\n    },\n    pages: {\n      options: {\n        layout: 'default.hbs'\n      },\n      files: {\n        './': ['src/templates/pages/index.hbs']\n      }\n    }\n  }\n};\n```\n\n## Tables\nTables are created by adding pipes as dividers between each cell, and by adding a line of dashes (also separated by bars) beneath the header. Note that the pipes do not need to be vertically aligned.\n\n\n```markdown\n| Option | Description |\n| ------ | ----------- |\n| data   | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext    | extension to be used for dest files. |\n```\n\nRenders to:\n\n| Option | Description |\n| ------ | ----------- |\n| data   | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext    | extension to be used for dest files. |\n\nAnd this HTML:\n\n```html\n<table>\n  <tr>\n    <th>Option</th>\n    <th>Description</th>\n  </tr>\n  <tr>\n    <td>data</td>\n    <td>path to data files to supply the data that will be passed into templates.</td>\n  </tr>\n  <tr>\n    <td>engine</td>\n    <td>engine to be used for processing templates. Handlebars is the default.</td>\n  </tr>\n  <tr>\n    <td>ext</td>\n    <td>extension to be used for dest files.</td>\n  </tr>\n</table>\n```\n\n### Right aligned text\n\nAdding a colon on the right side of the dashes below any heading will right align text for that column.\n\n```markdown\n| Option | Description |\n| ------:| -----------:|\n| data   | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext    | extension to be used for dest files. |\n```\n\n| Option | Description |\n| ------:| -----------:|\n| data   | path to data files to supply the data that will be passed into templates. |\n| engine | engine to be used for processing templates. Handlebars is the default. |\n| ext    | extension to be used for dest files. |\n\n## Links\n\n### Basic link\n\n```markdown\n[Assemble](http://assemble.io)\n```\n\nRenders to (hover over the link, there is no tooltip):\n\n[Assemble](http://assemble.io)\n\nHTML:\n\n```html\n<a href=\"http://assemble.io\">Assemble</a>\n```\n\n\n### Add a title\n\n```markdown\n[Upstage](https://github.com/upstage/ \"Visit Upstage!\")\n```\n\nRenders to (hover over the link, there should be a tooltip):\n\n[Upstage](https://github.com/upstage/ \"Visit Upstage!\")\n\nHTML:\n\n```html\n<a href=\"https://github.com/upstage/\" title=\"Visit Upstage!\">Upstage</a>\n```\n\n### Named Anchors\n\nNamed anchors enable you to jump to the specified anchor point on the same page. For example, each of these chapters:\n\n```markdown\n# Table of Contents\n  * [Chapter 1](#chapter-1)\n  * [Chapter 2](#chapter-2)\n  * [Chapter 3](#chapter-3)\n```\nwill jump to these sections:\n\n```markdown\n## Chapter 1 <a id=\"chapter-1\"></a>\nContent for chapter one.\n\n## Chapter 2 <a id=\"chapter-2\"></a>\nContent for chapter one.\n\n## Chapter 3 <a id=\"chapter-3\"></a>\nContent for chapter one.\n```\n**NOTE** that specific placement of the anchor tag seems to be arbitrary. They are placed inline here since it seems to be unobtrusive, and it works.\n\n\n## Images {#images}\nImages have a similar syntax to links but include a preceding exclamation point.\n\n```markdown\n![Minion](http://octodex.github.com/images/minion.png)\n```\n![Minion](http://octodex.github.com/images/minion.png)\n\nor\n```markdown\n![Alt text](http://octodex.github.com/images/stormtroopocat.jpg \"The Stormtroopocat\")\n```\n![Alt text](http://octodex.github.com/images/stormtroopocat.jpg \"The Stormtroopocat\")\n\nLike links, Images also have a footnote style syntax\n\n### Alternative usage : note images\n\n```markdown\n![Alt text][id]\n```\n![Alt text][id]\n\nWith a reference later in the document defining the URL location:\n\n[id]: http://octodex.github.com/images/dojocat.jpg  \"The Dojocat\"\n\n    [id]: http://octodex.github.com/images/dojocat.jpg  \"The Dojocat\"\n\n### Resizing image\n\nAdd HTTP parameters `width` and/or `height` to the link image to resize the image. Values are CSS values (default is `auto`).\n\n```markdown\n![Minion](http://octodex.github.com/images/minion.png?width=20pc)\n```\n\n![Minion](http://octodex.github.com/images/minion.png?width=20pc)\n\n```markdown\n![Minion](http://octodex.github.com/images/minion.png?height=50px)\n```\n\n![Minion](http://octodex.github.com/images/minion.png?height=50px)\n\n```markdown\n![Minion](http://octodex.github.com/images/minion.png?height=50px&width=300px)\n```\n\n![Minion](http://octodex.github.com/images/minion.png?height=50px&width=300px)\n\n### Add CSS classes\n\nAdd a HTTP `classes` parameter to the link image to add CSS classes. `shadow`and `border` are available but you could define other ones.\n\n```markdown\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?classes=shadow)\n```\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?width=40pc&classes=shadow)\n\n```markdown\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?classes=border)\n```\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?width=40pc&classes=border)\n\n```markdown\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?classes=border,shadow)\n```\n![stormtroopocat](http://octodex.github.com/images/stormtroopocat.jpg?width=40pc&classes=border,shadow)\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/menushortcuts.en.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Menu extra shortcuts\nweight: 25\n---\n\nYou can define additional menu entries or shortcuts in the navigation menu without any link to content.\n\n## Basic configuration\n\nEdit the website configuration `config.toml` and add a `[[menu.shortcuts]]` entry for each link your want to add.\n\nExample from the current website:\n\n    [[menu.shortcuts]] \n    name = \"<i class='fa fa-github'></i> Github repo\"\n    identifier = \"ds\"\n    url = \"https://github.com/matcornic/hugo-theme-learn\"\n    weight = 10\n\n    [[menu.shortcuts]]\n    name = \"<i class='fa fa-camera'></i> Showcases\"\n    url = \"/showcase\"\n    weight = 11\n\n    [[menu.shortcuts]]\n    name = \"<i class='fa fa-bookmark'></i> Hugo Documentation\"\n    identifier = \"hugodoc\"\n    url = \"https://gohugo.io/\"\n    weight = 20\n\n    [[menu.shortcuts]]\n    name = \"<i class='fa fa-bullhorn'></i> Credits\"\n    url = \"/credits\"\n    weight = 30\n\nBy default, shortcuts are preceded by a title. This title can be disabled by setting `disableShortcutsTitle=true`. \nHowever, if you want to keep the title but change its value, it can be overriden by changing your local i18n translation string configuration. \n\nFor example, in your local `i18n/en.toml` file, add the following content\n\n    [Shortcuts-Title]\n    other = \"<Your value>\"\n\nRead more about [hugo menu](https://gohugo.io/extras/menus/) and [hugo i18n translation strings](https://gohugo.io/content-management/multilingual/#translation-of-strings)\n\n## Configuration for Multilingual mode {#i18n}\n\nWhen using a multilingual website, you can set different menus for each language. In the `config.toml` file, prefix your menu configuration by `Languages.<language-id>`. \n\n\nExample from the current website:\n\n    [Languages]\n    [Languages.en]\n    title = \"Documentation for Hugo Learn Theme\"\n    weight = 1\n    languageName = \"English\"\n\n    [[Languages.en.menu.shortcuts]] \n    name = \"<i class='fa fa-github'></i> Github repo\"\n    identifier = \"ds\"\n    url = \"https://github.com/matcornic/hugo-theme-learn\"\n    weight = 10\n\n    [[Languages.en.menu.shortcuts]]\n    name = \"<i class='fa fa-camera'></i> Showcases\"\n    url = \"/showcase\"\n    weight = 11\n\n    [[Languages.en.menu.shortcuts]]\n    name = \"<i class='fa fa-bookmark'></i> Hugo Documentation\"\n    identifier = \"hugodoc\"\n    url = \"https://gohugo.io/\"\n    weight = 20\n\n    [[Languages.en.menu.shortcuts]]\n    name = \"<i class='fa fa-bullhorn'></i> Credits\"\n    url = \"/credits\"\n    weight = 30\n\n    [Languages.fr]\n    title = \"Documentation du thème Hugo Learn\"\n    weight = 2\n    languageName = \"Français\"\n\n    [[Languages.fr.menu.shortcuts]]\n    name = \"<i class='fa fa-github'></i> Repo Github\"\n    identifier = \"ds\"\n    url = \"https://github.com/matcornic/hugo-theme-learn\"\n    weight = 10\n\n    [[Languages.fr.menu.shortcuts]]\n    name = \"<i class='fa fa-camera'></i> Vitrine\"\n    url = \"/showcase\"\n    weight = 11\n\n    [[Languages.fr.menu.shortcuts]]\n    name = \"<i class='fa fa-bookmark'></i> Documentation Hugo\"\n    identifier = \"hugodoc\"\n    url = \"https://gohugo.io/\"\n    weight = 20\n\n    [[Languages.fr.menu.shortcuts]]\n    name = \"<i class='fa fa-bullhorn'></i> Crédits\"\n    url = \"/credits\"\n    weight = 30\n\nRead more about [hugo menu](https://gohugo.io/extras/menus/) and [hugo multilingual menus](https://gohugo.io/content-management/multilingual/#menus)"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/menushortcuts.fr.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Raccourcis du menu\nweight: 25\n---\n\nVous pouvez définir des entrées ou raccourcis supplémentaires dans le menu sans avoir besoin d'être lié à un contenu du site.\n\n## Configuration simple\n\nEditez le fichier de configuration `config.toml` et ajoutez une entrée `[[menu.shortcuts]]` pour chaque lien que vous voulez ajouter.\n\nExemple pour ce site:\n\n    [[menu.shortcuts]] \n    name = \"<i class='fa fa-github'></i> Github repo\"\n    identifier = \"ds\"\n    url = \"https://github.com/matcornic/hugo-theme-learn\"\n    weight = 10\n\n    [[menu.shortcuts]]\n    name = \"<i class='fa fa-camera'></i> Showcases\"\n    url = \"/showcase\"\n    weight = 11\n\n    [[menu.shortcuts]]\n    name = \"<i class='fa fa-bookmark'></i> Hugo Documentation\"\n    identifier = \"hugodoc\"\n    url = \"https://gohugo.io/\"\n    weight = 20\n\n    [[menu.shortcuts]]\n    name = \"<i class='fa fa-bullhorn'></i> Credits\"\n    url = \"/credits\"\n    weight = 30\n\nPar défaut, les raccourcis sont précédés par un titre. Ce titre peut être désactivé en ajouter le paramètre `disableShortcutsTitle=true` dans la section `params` de votre `config.toml`. \nCependant, si vous voulez garder le titre mais changer sa valeur, vous pouvez modifier votre configuration multilangue locale en changeant les *translation string*. \n\nPar exemple, dans votre fichier local `i18n/en.toml`, ajouter le contenu\n\n    [Shortcuts-Title]\n    other = \"<Votre valeur>\"\n\nPlus d'infos sur [les menus Hugo](https://gohugo.io/extras/menus/) et sur [les translations strings](https://gohugo.io/content-management/multilingual/#translation-of-strings)\n\n## Configuration pour le mode multi-langue {#i18n}\n\nQuand vous utilisez un site multi-langue, vous pouvez avoir des menus différents pour chaque langage. Dans le fichier de configuration `config.toml`, préfixez votre configuration par `Languages.<language-id>`. \n\n\nPar exemple, avec ce site :\n\n    [Languages]\n    [Languages.en]\n    title = \"Documentation for Hugo Learn Theme\"\n    weight = 1\n    languageName = \"English\"\n\n    [[Languages.en.menu.shortcuts]] \n    name = \"<i class='fa fa-github'></i> Github repo\"\n    identifier = \"ds\"\n    url = \"https://github.com/matcornic/hugo-theme-learn\"\n    weight = 10\n\n    [[Languages.en.menu.shortcuts]]\n    name = \"<i class='fa fa-camera'></i> Showcases\"\n    url = \"/showcase\"\n    weight = 11\n\n    [[Languages.en.menu.shortcuts]]\n    name = \"<i class='fa fa-bookmark'></i> Hugo Documentation\"\n    identifier = \"hugodoc\"\n    url = \"https://gohugo.io/\"\n    weight = 20\n\n    [[Languages.en.menu.shortcuts]]\n    name = \"<i class='fa fa-bullhorn'></i> Credits\"\n    url = \"/credits\"\n    weight = 30\n\n    [Languages.fr]\n    title = \"Documentation du thème Hugo Learn\"\n    weight = 2\n    languageName = \"Français\"\n\n    [[Languages.fr.menu.shortcuts]]\n    name = \"<i class='fa fa-github'></i> Repo Github\"\n    identifier = \"ds\"\n    url = \"https://github.com/matcornic/hugo-theme-learn\"\n    weight = 10\n\n    [[Languages.fr.menu.shortcuts]]\n    name = \"<i class='fa fa-camera'></i> Vitrine\"\n    url = \"/showcase\"\n    weight = 11\n\n    [[Languages.fr.menu.shortcuts]]\n    name = \"<i class='fa fa-bookmark'></i> Documentation Hugo\"\n    identifier = \"hugodoc\"\n    url = \"https://gohugo.io/\"\n    weight = 20\n\n    [[Languages.fr.menu.shortcuts]]\n    name = \"<i class='fa fa-bullhorn'></i> Crédits\"\n    url = \"/credits\"\n    weight = 30\n\nPlus d'infos sur [les menus Hugo](https://gohugo.io/extras/menus/) et les [menus multi-langue Hugo](https://gohugo.io/content-management/multilingual/#menus)"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/pages/_index.en.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Pages organization\nweight: 5\n---\n\nIn **Hugo**, pages are the core of your site. Once it is configured, pages are definitely the added value to your documentation site.\n\n## Folders\n\nOrganize your site like [any other Hugo project](https://gohugo.io/content/organization/). Typically, you will have a *content* folder with all your pages.\n\n    content\n    ├── level-one \n    │   ├── level-two\n    │   │   ├── level-three\n    │   │   │   ├── level-four\n    │   │   │   │   ├── _index.md       <-- /level-one/level-two/level-three/level-four\n    │   │   │   │   ├── page-4-a.md     <-- /level-one/level-two/level-three/level-four/page-4-a\n    │   │   │   │   ├── page-4-b.md     <-- /level-one/level-two/level-three/level-four/page-4-b\n    │   │   │   │   └── page-4-c.md     <-- /level-one/level-two/level-three/level-four/page-4-c\n    │   │   │   ├── _index.md           <-- /level-one/level-two/level-three\n    │   │   │   ├── page-3-a.md         <-- /level-one/level-two/level-three/page-3-a\n    │   │   │   ├── page-3-b.md         <-- /level-one/level-two/level-three/page-3-b\n    │   │   │   └── page-3-c.md         <-- /level-one/level-two/level-three/page-3-c\n    │   │   ├── _index.md               <-- /level-one/level-two\n    │   │   ├── page-2-a.md             <-- /level-one/level-two/page-2-a\n    │   │   ├── page-2-b.md             <-- /level-one/level-two/page-2-b\n    │   │   └── page-2-c.md             <-- /level-one/level-two/page-2-c\n    │   ├── _index.md                   <-- /level-one\n    │   ├── page-1-a.md                 <-- /level-one/page-1-a\n    │   ├── page-1-b.md                 <-- /level-one/page-1-b\n    │   └── page-1-c.md                 <-- /level-one/page-1-c\n    ├── _index.md                       <-- /\n    └── page-top.md                     <-- /page-top\n\n{{% notice note %}}\n`_index.md` is required in each folder, it’s your “folder home page”\n{{% /notice %}}\n\n## Types\n\n**Hugo-theme-learn** defines two types of pages. *Default* and *Chapter*. Both can be used at any level of the documentation, the only difference being layout display.\n\nA **Chapter** displays a page meant to be used as introduction for a set of child pages. Commonly, it contains a simple title and a catch line to define content that can be found under it.\nYou can define any HTML as prefix for the menu. In the example below, it's just a number but that could be an [icon](https://fortawesome.github.io/Font-Awesome/).\n\n![Chapter page](/cont/pages/images/pages-chapter.png?width=50pc)\n\n```markdown\n+++\ntitle = \"Basics\"\nchapter = true\nweight = 5\npre = \"<b>1. </b>\"\n+++\n\n### Chapter 1\n\n# Basics\n\nDiscover what this Hugo theme is all about and the core-concepts behind it.\n```\n\nTo tell **Hugo-theme-learn** to consider a page as a chapter, set `chapter=true` in the Front Matter of the page.\n\nA **Default** page is any other content page.\n\n![Default page](/cont/pages/images/pages-default.png?width=50pc)\n\n```toml\n+++\ntitle = \"Installation\"\nweight = 15\n+++\n```\n\nThe following steps are here to help you initialize your new website. If you don't know Hugo at all, we strongly suggest you to train by following this [great documentation for beginners](https://gohugo.io/overview/quickstart/).\n\n## Create your project\n\nHugo provides a `new` command to create a new website.\n\n```\nhugo new site <new_project>\n```\n\n**Hugo-theme-learn** provides [archetypes]({{< relref \"cont/archetypes.fr.md\" >}}) to help you create this kind of pages.\n\n## Front Matter configuration\n\nEach Hugo page has to define a [Front Matter](https://gohugo.io/content/front-matter/) in *yaml*, *toml* or *json*.\n\n**Hugo-theme-learn** uses the following parameters on top of Hugo ones :\n\n```toml\n+++\n# Table of content (toc) is enabled by default. Set this parameter to true to disable it.\n# Note: Toc is always disabled for chapter pages\ndisableToc = \"false\"\n# If set, this will be used for the page's menu entry (instead of the `title` attribute)\nmenuTitle = \"\"\n# The title of the page in menu will be prefixed by this HTML content\npre = \"\"\n# The title of the page in menu will be postfixed by this HTML content\npost = \"\"\n# Set the page as a chapter, changing the way it's displayed\nchapter = false\n# Hide a menu entry by setting this to true\nhidden = false\n# Display name of this page modifier. If set, it will be displayed in the footer. \nLastModifierDisplayName = \"\"\n# Email of this page modifier. If set with LastModifierDisplayName, it will be displayed in the footer\nLastModifierEmail = \"\"\n+++\n```\n\n### Add icon to a menu entry\n\nIn the page frontmatter, add a `pre` param to insert any HTML code before the menu label. The example below uses the Github icon.\n\n```toml\n+++\ntitle = \"Github repo\"\npre = \"<i class='fa fa-github'></i> \"\n+++\n```\n\n![Title with icon](/cont/pages/images/frontmatter-icon.png)\n\n### Ordering sibling menu/page entries\n\nHugo provides a [flexible way](https://gohugo.io/content/ordering/) to handle order for your pages.\n\nThe simplest way is to set `weight` parameter to a number.\n\n```toml\n+++\ntitle = \"My page\"\nweight = 5\n+++\n```\n\n### Using a custom title for menu entries\n\nBy default, **Hugo-theme-learn** will use a page's `title` attribute for the menu item (or `linkTitle` if defined).\n\nBut a page's title has to be descriptive on its own while the menu is a hierarchy.  \nWe've added the `menuTitle` parameter for that purpose:\n\nFor example (for a page named `content/install/linux.md`): \n\n```toml\n+++\ntitle = \"Install on Linux\"\nmenuTitle = \"Linux\"\n+++\n```\n\n## Homepage\n\nTo configure your home page, you basically have three choices:\n\n1. Create an `_index.md` document in `content` folder and fill the file with *Markdown content*\n2. Create an `index.html` file in the `static` folder and fill the file with *HTML content*\n3. Configure your server to automatically redirect home page to one your documentation page\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/cont/pages/_index.fr.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Organisation des pages\nweight: 5\n---\n\nDans **Hugo**, les pages sont le coeur de votre site. Une fois configurées, les pages sont la valeur ajoutée de votre site de documentation.\n\n## Dossiers\n\nOrganisez votre site comment n'importe quel autre [projet Hugo](https://gohugo.io/content/organization/). Typiquement, vous allez avoir un dossier *content* avec vos pages.\n\n    content\n    ├── niveau-un \n    │   ├── niveau-deux\n    │   │   ├── niveau-trois\n    │   │   │   ├── niveau-quatre\n    │   │   │   │   ├── _index.md       <-- /niveau-un/niveau-deux/niveau-trois/niveau-quatre\n    │   │   │   │   ├── page-4-a.md     <-- /niveau-un/niveau-deux/niveau-trois/niveau-quatre/page-4-a\n    │   │   │   │   ├── page-4-b.md     <-- /niveau-un/niveau-deux/niveau-trois/niveau-quatre/page-4-b\n    │   │   │   │   └── page-4-c.md     <-- /niveau-un/niveau-deux/niveau-trois/niveau-quatre/page-4-c\n    │   │   │   ├── _index.md           <-- /niveau-un/niveau-deux/niveau-trois\n    │   │   │   ├── page-3-a.md         <-- /niveau-un/niveau-deux/niveau-trois/page-3-a\n    │   │   │   ├── page-3-b.md         <-- /niveau-un/niveau-deux/niveau-trois/page-3-b\n    │   │   │   └── page-3-c.md         <-- /niveau-un/niveau-deux/niveau-trois/page-3-c\n    │   │   ├── _index.md               <-- /niveau-un/niveau-deux\n    │   │   ├── page-2-a.md             <-- /niveau-un/niveau-deux/page-2-a\n    │   │   ├── page-2-b.md             <-- /niveau-un/niveau-deux/page-2-b\n    │   │   └── page-2-c.md             <-- /niveau-un/niveau-deux/page-2-c\n    │   ├── _index.md                   <-- /niveau-un\n    │   ├── page-1-a.md                 <-- /niveau-un/page-1-a\n    │   ├── page-1-b.md                 <-- /niveau-un/page-1-b\n    │   └── page-1-c.md                 <-- /niveau-un/page-1-c\n    ├── _index.md                       <-- /\n    └── premiere-page.md                <-- /premiere-page\n\n{{% notice note %}}\nLe fichier `_index.md` est obligatoire dans chaque dossier, c'est en quelques rotes votre page d'accueil pour le dossier.\n{{% /notice %}}\n\n## Types\n\n**Hugo-theme-learn** définit deux types de pages. *Défaut* et *Chapitre*. Les deux sont utilisables à n'importe quel niveau du site, la seule différence est dans l'affichage.\n\nUn **Chapitre** affiche une page vouée à être une introduction pour un ensemble de pages filles. Habituellement, il va seulement contenir un titre et un résumé de la section.\nVous pouvez définir n'importe quel contenu HTML comme préfixe de l'entrée du menu. Dans l'exemple ci-dessous, c'est juste un nombre mais vous pourriez utiliser une [icône](https://fortawesome.github.io/Font-Awesome/).\n\n![Page Chapitre](/cont/pages/images/pages-chapter.png?width=50pc)\n\n```markdown\n+++\ntitle = \"Démarrage\"\nweight = 5\npre = \"<b>1. </b>\"\nchapter = true\n+++\n\n### Chapitre 1\n\n# Démarrage\n\nDécouvrez comment utiliser ce thème Hugo et apprenez en les concepts\n```\n\nPour dire à **Hugo-theme-learn** de considérer la page comme un chapitre, configure `chapter=true` dans le Front Matter de la page.\n\nUne page **Défaut** est n'importe quelle autre page.\n\n![Page défaut](/cont/pages/images/pages-default.png?width=50pc)\n\n    +++\n    title = \"Installation\"\n    weight = 15\n    +++\n\n    The following steps are here to help you initialize your new website. If you don't know Hugo at all, we strongly suggest you to train by following this [great documentation for beginners](https://gohugo.io/overview/quickstart/).\n\n    ## Create your project\n\n    Hugo provides a `new` command to create a new website.\n\n    ```\n    hugo new site <new_project>\n    ```\n\n**Hugo-theme-learn** fournit des [archétypes]({{< relref \"cont/archetypes.fr.md\" >}}) pour vous aider à créer ce type de pages.\n\n## Configuration des Front Matter\n\nChaque page Hugo doit définir un [Front Matter](https://gohugo.io/content/front-matter/) dans le format *yaml*, *toml* ou *json*.\n\n**Hugo-theme-learn** utilise les paramètres suivant en plus de ceux définis par Hugo:\n\n```toml\n+++\n# Le Sommaire (table of content = toc) est activé par défaut. Modifier ce paramètre à true pour le désactiver.\n# Note: Le sommaire est toujours désactivé pour les chapitres\ndisableToc = \"false\"\n# Le titre de la page dans le menu sera préfixé par ce contentu HTML\npre = \"\"\n# Le titre de la page dans le menu sera suffixé par ce contentu HTML\npost = \"\"\n# Modifier le type de la page pour changer l'affichage\nchapter = false\n# Cache la page du menu\nhidden = false\n# Nom de la personne qui a modifié la page. Quand configuré, sera affiché dans le pied de page. \nLastModifierDisplayName = \"\"\n# Email de la personne qui a modifié la page. Quand configuré, sera affiché dans le pied de page.\nLastModifierEmail = \"\"\n+++\n```\n\n### Ajouter une icône à une entrée du menu\n\nDans le Front Matter, ajouter un paramètre `pre` pour insérer du code HTML qui s'affichera avant le label du menu. L'exemple ci-dessous utilise l'icône de Github.\n\n```toml\n+++\ntitle = \"Repo Github\"\npre = \"<i class='fa fa-github'></i> \"\n+++\n```\n\n![Titre avec icône](/cont/pages/images/frontmatter-icon.png)\n\n### Ordonner les entrées dans le menu\n\nHugo permet de modifier facilement [l'ordre des menu](https://gohugo.io/content/ordering/).\n\nLa manière la plus simple est de configurer le paramètre `weight` avec un nombre.\n\n```toml\n+++\ntitle = \"Ma page\"\nweight = 5\n+++\n```\n\n## Page d'accueil\n\nPour configurer votre page d'accueil, vous avez trois choix:\n\n1. Créer une page `_index.md` dans le dossier `content` et remplissez le fichier avec du *contenu Markdown*\n2. Créer une page `index.html` dans le dossier `static` et remplissez le fichier avec du *contenu HTML*\n3. Configurez votre serveur pour automatiquement rediriger la page d'accueil vers l'une de vos pages.\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/credits.en.md",
    "content": "---\ntitle: Credits\ndisableToc: true\n---\n\n## Contributors\n\nThanks to them <i class=\"fa fa-heart\"></i> for making Open Source Software a better place !\n\n{{% ghcontributors \"https://api.github.com/repos/matcornic/hugo-theme-learn/contributors?per_page=100\" %}}\n\nAnd a special thanks to [@vjeantet](https://github.com/vjeantet) for his work on [docdock](https://github.com/vjeantet/hugo-theme-docdock), a fork of hugo-theme-learn. v2.0.0 of this theme is inspired by his work.\n\n## Packages and libraries\n* [mermaid](https://knsv.github.io/mermaid) - generation of diagram and flowchart from text in a similar manner as markdown\n* [font awesome](http://fontawesome.io/) - the iconic font and CSS framework\n* [jQuery](https://jquery.com) - The Write Less, Do More, JavaScript Library\n* [lunr](https://lunrjs.com) - Lunr enables you to provide a great search experience without the need for external, server-side, search services...\n* [horsey](https://bevacqua.github.io/horsey/) - Progressive and customizable autocomplete component\n* [clipboard.js](https://zenorocha.github.io/clipboard.js) - copy text to clipboard\n* [highlight.js](https://highlightjs.org) - Javascript syntax highlighter\n* [modernizr](https://modernizr.com) - A JavaScript toolkit that allows web developers to use new CSS3 and HTML5 features while maintaining a fine level of control over browsers that don't support\n\n## Tooling\n\n* [Netlify](https://www.netlify.com) - Continuous deployement and hosting of this documentation\n* [Hugo](https://gohugo.io/)\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/credits.fr.md",
    "content": "---\ntitle: Crédits\ndisableToc: true\n---\n\n## Contributeurs\n\nMerci à eux <i class=\"fa fa-heart\"></i> de rendre le monde Open Source meilleur  !\n\n{{% ghcontributors \"https://api.github.com/repos/matcornic/hugo-theme-learn/contributors?per_page=100\" %}}\n\nEt un grand merci à [@vjeantet](https://github.com/vjeantet) pour son travail sur [docdock](https://github.com/vjeantet/hugo-theme-docdock), un fork de _hugo-theme-learn_. La v2.0.0 du thème est en grande partie inspirée de son travail.\n\n## Packages et librairies\n* [mermaid](https://knsv.github.io/mermaid) - géneration de diagrames et graphiques à partir de texte similaire à Markdown\n* [font awesome](http://fontawesome.io/) - Le framework de polices iconiques\n* [jQuery](https://jquery.com) - La plus connue des librairies Javascript\n* [lunr](https://lunrjs.com) - Lunr fournit des fonctions de recherche sans service externe\n* [horsey](https://bevacqua.github.io/horsey/) - Autocomplétion de composants (utiliser pour les suggestions de recherche)\n* [clipboard.js](https://zenorocha.github.io/clipboard.js) - Copier le texte dans le presse-papier\n* [highlight.js](https://highlightjs.org) - Mise en valeur de syntaxes\n* [modernizr](https://modernizr.com) - Une boite à outil Javascript qui permet aux développeurs d'utiliser les dernières fonctionnalités de CSS et HTML5, même sur de vieux navigateurs.\n\n## Outils\n\n* [Netlify](https://www.netlify.com) - Déploiement continue et hébergement de cette documentation\n* [Hugo](https://gohugo.io/)\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/_index.en.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Shortcodes\npre: \"<b>3. </b>\"\nweight: 15\n---\n\nHugo uses Markdown for its simple content format. However, there are a lot of things that Markdown doesn’t support well. You could use pure HTML to expand possibilities.\n\nBut this happens to be a bad idea. Everyone uses Markdown because it's pure and simple to read even non-rendered. You should avoid HTML to keep it as simple as possible.\n\nTo avoid this limitations, Hugo created [shortcodes](https://gohugo.io/extras/shortcodes/). A shortcode is a simple snippet inside a page.\n\n**Hugo-theme-learn** provides multiple shortcodes on top of existing ones.\n\n{{%children style=\"h2\" description=\"true\" %}}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/_index.fr.md",
    "content": "---\ndate: 2016-04-09T16:50:16+02:00\ntitle: Shortcodes\npre: \"<b>3. </b>\"\nweight: 15\n---\n\nHugo utilise Markdown pour son format simple. Cependant, il y a beaucoup de chose que Markdown ne supporte pas bien. On pourrait utiliser du HTML pur pour améliorer les capacité du Markdown.\n\nMais c'est probablement une mauvaise idée. Tout le monde utilise le Markdown parce que c'est pur et simple à lire même lorsqu'il est affiché en texte brut. Vous devez éviter le HTML autant que possible pour garder le contenu simple.\n\nCependant, pour éviter les limitations, Hugo a créé les [shortcodes](https://gohugo.io/extras/shortcodes/). Un shortcode est un bout de code (*snippet*) dans une page.\n\n**Hugo-theme-learn** fournit de multiple shortcodes en plus de ceux existant.\n\n{{%children style=\"h2\" description=\"true\" %}}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/attachments.en.md",
    "content": "---\ntitle: Attachments\ndescription : \"The Attachments shortcode displays a list of files attached to a page.\"\n---\n\nThe Attachments shortcode displays a list of files attached to a page.\n\n{{% attachments /%}}\n\n## Usage\n\nThe shortcurt lists files found in a **specific folder**.\nCurrently, it support two implementations for pages\n\n1. If your page is a markdown file, attachements must be place in a **folder** named like your page and ending with **.files**.\n\n    > * content\n    >   * _index.md\n    >   * page.files\n    >      * attachment.pdf\n    >   * page.md\n\n2. If your page is a **folder**, attachements must be place in a nested **'files'** folder.\n\n    > * content\n    >   * _index.md\n    >   * page\n    >      * index.md\n    >      * files\n    >          * attachment.pdf\n\nBe aware that if you use a multilingual website, you will need to have as many folders as languages.\n\nThat's all !\n\n### Parameters\n\n| Parameter | Default | Description |\n|:--|:--|:--|\n| title | \"Attachments\" | List's title  |\n| style | \"\" | Choose between \"orange\", \"grey\", \"blue\" and \"green\" for nice style |\n| pattern | \".*\" | A regular expressions, used to filter the attachments by file name. <br/><br/>The **pattern** parameter value must be [regular expressions](https://en.wikipedia.org/wiki/Regular_expression).\n\nFor example:\n\n* To match a file suffix of 'jpg', use **.*jpg** (not *.jpg).\n* To match file names ending in 'jpg' or 'png', use **.*(jpg|png)**\n\n### Examples\n\n#### List of attachments ending in pdf or mp4\n\n\n    {{%/*attachments title=\"Related files\" pattern=\".*(pdf|mp4)\"/*/%}}\n\nrenders as\n\n{{%attachments title=\"Related files\" pattern=\".*(pdf|mp4)\"/%}}\n\n#### Colored styled box\n\n    {{%/*attachments style=\"orange\" /*/%}}\n\nrenders as\n\n{{% attachments style=\"orange\" /%}}\n\n\n    {{%/*attachments style=\"grey\" /*/%}}\n\nrenders as \n\n{{% attachments style=\"grey\" /%}}\n\n    {{%/*attachments style=\"blue\" /*/%}}\n\nrenders as\n\n{{% attachments style=\"blue\" /%}}\n    \n    {{%/*attachments style=\"green\" /*/%}}\n\nrenders as\n\n{{% attachments style=\"green\" /%}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/attachments.fr.md",
    "content": "---\ntitle: Attachments (Pièces jointes)\ndescription : \"The Attachments shortcode displays a list of files attached to a page.\"\n---\n\nLe shortcode *Attachments* affiche une liste de pièces jointes d'une page.\n\n{{% attachments /%}}\n\n## Utilisation\n\nLe shortcode affiche la liste de fichiers trouvés dans un **dossier spécifique**\nA l'heure actuelle, il supporte deux implémentations\n\n1. Si votre page est un fichier Markdown, les pièces jointes doivent être placée dans un **dossier** nommé comme le nom de la page et suffixé par **.files**.\n\n    > * content\n    >   * _index.md\n    >   * page.files\n    >      * attachment.pdf\n    >   * page.md\n\n2. Si votre page est un **dossier**, les pièces jointes doivent être placées dans un dossier fils **'files'**.\n\n    > * content\n    >   * _index.md\n    >   * page\n    >      * index.md\n    >      * files\n    >          * attachment.pdf\n\nAttention, si votre site est multi-langue, vous devrez avec autant de dossier qu'il y a de langues.\n\nC'est tout !\n\n### Paramètres\n\n| Paramètre | Défaut | Description |\n|:--|:--|:--|\n| title | \"Pièces jointes\" | Titre de la liste  |\n| style | \"\" | Choisir entre \"orange\", \"grey\", \"blue\" et \"green\" pour un style plus sympa |\n| pattern | \".*\" | Une expression régulière, utilisée pour filtrer les pièces jointes par leur nom de fichier. <br/><br/>Le paramètre **pattern** doit être une [expression régulière](https://en.wikipedia.org/wiki/Regular_expression).\n\nPar exemple:\n\n* Pour trouver les fichiers avec le suffixe 'jpg', utilisez **.*jpg** (pas *.jpg).\n* Pour trouver les fichiers avec les suffixe 'jpg' ou 'png', utilisez **.*(jpg|png)**\n\n### Exemples\n\n#### Lister les pièces jointes de type pdf ou mp4\n\n\n    {{%/*attachments title=\"Fichiers associés\" pattern=\".*(pdf|mp4)\"/*/%}}\n\ns'affiche comme\n\n{{%attachments title=\"Fichiers associés\" pattern=\".*(pdf|mp4)\"/%}}\n\n#### Modifier le style\n\n    {{%/*attachments style=\"orange\" /*/%}}\n\ns'affiche comme\n\n{{% attachments style=\"orange\" /%}}\n\n\n    {{%/*attachments style=\"grey\" /*/%}}\n\ns'affiche comme\n\n{{% attachments style=\"grey\" /%}}\n\n    {{%/*attachments style=\"blue\" /*/%}}\n\ns'affiche comme\n\n{{% attachments style=\"blue\" /%}}\n    \n    {{%/*attachments style=\"green\" /*/%}}\n\ns'affiche comme\n\n{{% attachments style=\"green\" /%}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/button.en.md",
    "content": "---\ntitle: Button\ndescription : \"Nice buttons on your page.\"\n---\n\nA button is a just a clickable button with optional icon.\n\n```\n{{%/* button href=\"https://getgrav.org/\" */%}}Get Grav{{%/* /button */%}}\n{{%/* button href=\"https://getgrav.org/\" icon=\"fa fa-download\" */%}}Get Grav with icon{{%/* /button */%}}\n{{%/* button href=\"https://getgrav.org/\" icon=\"fa fa-download\" icon-position=\"right\" */%}}Get Grav with icon right{{%/* /button */%}}\n```\n\n{{% button href=\"https://getgrav.org/\" %}}Get Grav{{% /button %}}\n{{% button href=\"https://getgrav.org/\" icon=\"fa fa-download\" %}}Get Grav with icon{{% /button %}}\n{{% button href=\"https://getgrav.org/\" icon=\"fa fa-download\" icon-position=\"right\" %}}Get Grav with icon right{{% /button %}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/button.fr.md",
    "content": "---\ntitle: Button (Bouton)\ndescription : \"De beaux boutons sur votre page.\"\n---\n\nLe shortcode *button* est simplement un bouton cliquable avec une icône optionnelle.\n\n```\n{{%/* button href=\"https://getgrav.org/\" */%}}Téléchargez Grav{{%/* /button */%}}\n{{%/* button href=\"https://getgrav.org/\" icon=\"fa fa-download\" */%}}Téléchargez Grav avec icône{{%/* /button */%}}\n{{%/* button href=\"https://getgrav.org/\" icon=\"fa fa-download\" icon-position=\"right\" */%}}Téléchargez Grav avec icône à droite{{%/* /button */%}}\n```\n\n{{% button href=\"https://getgrav.org/\" %}}Téléchargez Grav{{% /button %}}\n{{% button href=\"https://getgrav.org/\" icon=\"fa fa-download\" %}}Téléchargez Grav avec icône{{% /button %}}\n{{% button href=\"https://getgrav.org/\" icon=\"fa fa-download\" icon-position=\"right\" %}}Téléchargez Grav avec icône à droite{{% /button %}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/_index.en.md",
    "content": "---\ntitle : Children\ndescription : List the child pages of a page\n---\n\nUse the children shortcode to list the child pages of a page and the further descendants (children's children). By default, the shortcode displays links to the child pages.\n\n## Usage\n\n| Parameter | Default | Description |\n|:--|:--|:--|\n| page | _current_ | Specify the page name (section name) to display children for |\n| style | \"li\" | Choose the style used to display descendants. It could be any HTML tag name |\n| showhidden | \"false\" | When true, child pages hidden from the menu will be displayed |\n| description  | \"false\" | Allows you to include a short text under each page in the list.<br/>when no description exists for the page, children shortcode takes the first 70 words of your content. [read more info about summaries on gohugo.io](https://gohugo.io/content/summaries/)  |\n| depth | 1 | Enter a number to specify the depth of descendants to display. For example, if the value is 2, the shortcode will display 2 levels of child pages. <br/> **Tips:** set 999 to get all descendants|\n| sort | none | Sort Children By<br><li><strong>Weight</strong> - to sort on menu order</li><li><strong>Name</strong> - to sort alphabetically on menu label</li><li><strong>Identifier</strong> - to sort alphabetically on identifier set in frontmatter</li><li><strong>URL</strong> - URL</li> |\n\n## Demo\n\n\t{{%/* children  */%}}\n\n{{% children %}}\n\n\t{{%/* children description=\"true\"   */%}}\n\n{{%children description=\"true\"   %}}\n\n\t{{%/* children depth=\"3\" showhidden=\"true\" */%}}\n\n{{% children depth=\"3\" showhidden=\"true\" %}}\n\n\t{{%/* children style=\"h2\" depth=\"3\" description=\"true\" */%}}\n\n{{% children style=\"h2\" depth=\"3\" description=\"true\" %}}\n\n\t{{%/* children style=\"div\" depth=\"999\" */%}}\n\n{{% children style=\"div\" depth=\"999\" %}}\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/_index.fr.md",
    "content": "---\ntitle : Children (Pages filles)\ndescription : Liste les pages filles de la page\n---\n\nUtilisez le shortcode *children* pour lister les pages filles de la page et tous ses déscendants (pages filles de pages filles). Par défaut, le shortcode affiche des liens vers les pages filles.\n\n## Utilisation\n\n| Paramètre | Défaut | Description |\n|:--|:--|:--|\n| page | _current_ | Spécifie le nom de la page (nom de la section) à afficher |\n| style | \"li\" | Choisi le style à utiliser pour afficher les descendants. Cela peut être n'importe quel balise HTML |\n| showhidden | \"false\" | Quand *true*, pages filles cachées dans le menu seront affichées quand même |\n| description  | \"false\" | Permet d'inclure le texte de la description de la page sous chaque entré de la liste.<br/>quand aucune description existe pour la page, le shortcode prend les 70 premiers mots du contenu. [plus d'infos sur gohugo.io](https://gohugo.io/content/summaries/)  |\n| depth | 1 | Nombre de descendants à afficher. Par exemple, si la valeur est 2, le shortcode va afficher 2 niveaux de pages filels. <br/> **Astuce:** Utilisez 999 pour avoir tous les descendants|\n| sort | <rien> | Tri les pages filles par<br><li><strong>Weight</strong> - Poids</li><li><strong>Name</strong> - Nom</li><li><strong>Identifier</strong> - Trier alphabétiquement par identifiant configuré dans le front matter</li><li><strong>URL</strong> - URL</li> |\n\n## Démo\n\n\t{{%/* children  */%}}\n\n{{% children %}}\n\n\t{{%/* children description=\"true\"   */%}}\n\n{{%children description=\"true\"   %}}\n\n\t{{%/* children depth=\"3\" showhidden=\"true\" */%}}\n\n{{% children depth=\"3\" showhidden=\"true\" %}}\n\n\t{{%/* children style=\"h2\" depth=\"3\" description=\"true\" */%}}\n\n{{% children style=\"h2\" depth=\"3\" description=\"true\" %}}\n\n\t{{%/* children style=\"div\" depth=\"999\" */%}}\n\n{{% children style=\"div\" depth=\"999\" %}}\n\n\n\n\n\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-1/_index.en.md",
    "content": "+++\ntitle = \"page 1\"\ndescription = \"This is a demo child page\"\n+++\n\nThis is a demo child page"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-1/_index.fr.md",
    "content": "+++\ntitle = \"page 1\"\ndescription = \"Ceci est une page test\"\n+++\n\nCeci est une page de demo"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-1/children-1-1/_index.en.md",
    "content": "+++\ntitle = \"page 1-1\"\ndescription = \"This is a demo child page\"\n+++\n\nThis is a demo child page"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-1/children-1-1/_index.fr.md",
    "content": "+++\ntitle = \"page 1-1\"\ndescription = \"Ceci est une page test\"\n+++\n\nCeci est une page de demo"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-1/children-1-1/children-1-1-1/_index.en.md",
    "content": "+++\ntitle = \"page 1-1-1\"\ndescription = \"This is a demo child page\"\n+++\n\nThis is a demo child page"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-1/children-1-1/children-1-1-1/_index.fr.md",
    "content": "+++\ntitle = \"page 1-1-1\"\ndescription = \"Ceci est une page test\"\n+++\n\nCeci est une page de demo"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-1/children-1-1/children-1-1-1/children-1-1-1-1/_index.en.md",
    "content": "+++\ntitle = \"page 1-1-1-1\"\ndescription = \"This is a demo child page\"\n+++\n\nThis is a demo child page"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-1/children-1-1/children-1-1-1/children-1-1-1-1/_index.fr.md",
    "content": "+++\ntitle = \"page 1-1-1-1\"\ndescription = \"Ceci est une page test\"\n+++\n\nCeci est une page de demo"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-1/children-1-1/children-1-1-1/children-1-1-1-1/children-1-1-1-1-1/_index.en.md",
    "content": "+++\ntitle = \"page 1-1-1-1-1\"\ndescription = \"This is a demo child page\"\n+++\n\nThis is a demo child page"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-1/children-1-1/children-1-1-1/children-1-1-1-1/children-1-1-1-1-1/_index.fr.md",
    "content": "+++\ntitle = \"page 1-1-1-1-1\"\ndescription = \"Ceci est une page test\"\n+++\n\nCeci est une page de demo"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-2/_index.en.md",
    "content": "+++\ntitle = \"page 2\"\ndescription = \"\"\n+++\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n\ttempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n\tquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n\tconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n\tcillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n\tproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\t"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-2/_index.fr.md",
    "content": "+++\ntitle = \"page 2\"\ndescription = \"\"\n+++\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n\ttempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n\tquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n\tconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n\tcillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n\tproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\t"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-2/test3.en.md",
    "content": "+++\ntitle = \"page test 3\"\ndescription = \"This is a page test\"\n+++\n\nThis is a test 3 demo child page"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-2/test3.fr.md",
    "content": "+++\ntitle = \"page test 3\"\ndescription = \"Ceci est une page test\"\n+++\n\nCeci est une page de demo test 3"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-3/_index.en.md",
    "content": "+++\ntitle = \"page 3\"\ndescription = \"This is a demo child page\"\n+++\n\nThis is a demo child page, not displayed in the menu"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-3/_index.fr.md",
    "content": "+++\ntitle = \"page 3\"\ndescription = \"Ceci est une page test\"\n+++\n\nCeci est une page de demo"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-4/_index.en.md",
    "content": "+++\ntitle = \"page 4\"\ndescription = \"This is a demo child page\"\nhidden = true\n+++\n\nThis is a demo child page, not displayed in the menu"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/children-4/_index.fr.md",
    "content": "+++\ntitle = \"page 4\"\ndescription = \"Ceci est une page test\"\nhidden = true\n+++\n\nCeci est une page de demo"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/test.en.md",
    "content": "+++ \ntitle = \"page test\" \ndescription = \"This is a page test\"\n+++\n\nThis is a test demo child page"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/children/test.fr.md",
    "content": "+++ \ntitle = \"page test\" \ndescription = \"Ceci est une page test\"\n+++\n\nCeci est une page de demo"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/expand.en.md",
    "content": "---\ntitle : Expand\ndescription : \"Displays an expandable/collapsible section of text on your page\"\n---\n\nThe Expand shortcode displays an expandable/collapsible section of text on your page.\nHere is an example\n\n{{%expand%}}\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n{{%/expand%}}\n\n\n## Usage\n\n\nthis shortcode takes exactly one optional parameter to define the text that appears next to the expand/collapse icon. (default is \"Expand me...\")\n\n\t{{%/*expand \"Is this learn theme rocks ?\" */%}}Yes !.{{%/* /expand*/%}}\n\n{{%expand \"Is this learn theme rocks ?\" %}}Yes !{{% /expand%}}\n\n# Demo\n\n\t{{%/*expand*/%}}\n    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n\ttempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n\tquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n\tconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n\tcillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n\tproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n    {{%/* /expand*/%}}\n\n\n{{%expand%}}Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.{{% /expand%}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/expand.fr.md",
    "content": "---\ntitle : Expand\ndescription : \"Affiche une section de texte qui se plie et se déplie\"\n---\n\nLe shortcode *Expand* affiche une section de texte qui se plie et se déplie.\nCi-dessous un exemple.\n\n{{%expand%}}\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n{{%/expand%}}\n\n\n## Utilisation\n\n\nCe shortcode prends exactement un paramètre optionel pour définir le texte à côté de l'icone. (valeur par défaut est \"Déroulez-moi...\")\n\n\t{{%/*expand \"Est-ce que ce thème envoie du pâté ?\" */%}}Oui !.{{%/* /expand*/%}}\n\n{{%expand \"Est-ce que ce thème envoie du pâté ?\" %}}Oui !{{% /expand%}}\n\n# Demo\n\n\t{{%/*expand*/%}}\n    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n\ttempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n\tquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n\tconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n\tcillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n\tproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n    {{%/* /expand*/%}}\n\n\n{{%expand%}}Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.{{% /expand%}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/mermaid.en.md",
    "content": "---\ntitle : \"Mermaid\"\ndescription : \"Generation of diagram and flowchart from text in a similar manner as markdown\"\n---\n\n[Mermaid](https://mermaidjs.github.io/) is a library helping you to generate diagram and flowcharts from text, in a similar manner as Markdown.\n\nJust insert your mermaid code in the `mermaid` shortcode and that's it.\n\n## Flowchart example\n\t{{</*mermaid align=\"left\"*/>}}\n\tgraph LR;\n\t\tA[Hard edge] -->|Link text| B(Round edge)\n    \tB --> C{Decision}\n    \tC -->|One| D[Result one]\n    \tC -->|Two| E[Result two]\n    {{</* /mermaid */>}}\n\nrenders as\n\n{{<mermaid align=\"left\">}}\ngraph LR;\n\tA[Hard edge] -->|Link text| B(Round edge)\n    B --> C{Decision}\n    C -->|One| D[Result one]\n    C -->|Two| E[Result two]\n{{< /mermaid >}}\n\n## Sequence example\n\n\t{{</*mermaid*/>}}\n\tsequenceDiagram\n\t    participant Alice\n\t    participant Bob\n\t    Alice->>John: Hello John, how are you?\n\t    loop Healthcheck\n\t        John->John: Fight against hypochondria\n\t    end\n\t    Note right of John: Rational thoughts <br/>prevail...\n\t    John-->Alice: Great!\n\t    John->Bob: How about you?\n\t    Bob-->John: Jolly good!\n\t{{</* /mermaid */>}}\n\nrenders as\n\n{{<mermaid>}}\nsequenceDiagram\n    participant Alice\n    participant Bob\n    Alice->>John: Hello John, how are you?\n    loop Healthcheck\n        John->John: Fight against hypochondria\n    end\n    Note right of John: Rational thoughts <br/>prevail...\n    John-->Alice: Great!\n    John->Bob: How about you?\n    Bob-->John: Jolly good!\n{{< /mermaid >}}\n\n## GANTT Example\n\n\t{{</*mermaid*/>}}\n\tgantt\n\t        dateFormat  YYYY-MM-DD\n\t        title Adding GANTT diagram functionality to mermaid\n\t        section A section\n\t        Completed task            :done,    des1, 2014-01-06,2014-01-08\n\t        Active task               :active,  des2, 2014-01-09, 3d\n\t        Future task               :         des3, after des2, 5d\n\t        Future task2               :         des4, after des3, 5d\n\t        section Critical tasks\n\t        Completed task in the critical line :crit, done, 2014-01-06,24h\n\t        Implement parser and jison          :crit, done, after des1, 2d\n\t        Create tests for parser             :crit, active, 3d\n\t        Future task in critical line        :crit, 5d\n\t        Create tests for renderer           :2d\n\t        Add to mermaid                      :1d\n\t{{</* /mermaid */>}}\n\n\nrender as\n\n{{<mermaid>}}\ngantt\n        dateFormat  YYYY-MM-DD\n        title Adding GANTT diagram functionality to mermaid\n        section A section\n        Completed task            :done,    des1, 2014-01-06,2014-01-08\n        Active task               :active,  des2, 2014-01-09, 3d\n        Future task               :         des3, after des2, 5d\n        Future task2               :         des4, after des3, 5d\n        section Critical tasks\n        Completed task in the critical line :crit, done, 2014-01-06,24h\n        Implement parser and jison          :crit, done, after des1, 2d\n        Create tests for parser             :crit, active, 3d\n        Future task in critical line        :crit, 5d\n        Create tests for renderer           :2d\n        Add to mermaid                      :1d\n{{</mermaid>}}\n\n\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/mermaid.fr.md",
    "content": "---\ntitle : \"Mermaid\"\ndescription : \"Génération de diagrammes à partir de texte, dans le même style que Markdown\"\n---\n\n[Mermaid](https://mermaidjs.github.io/) est une bibliothèque Javascript qui permet de générer des diagrammes (séquence, état, gantt, etc.) à partir de texte, dans le même style que Markdown.\n\nInsérer votre code Mermaid dans un shortcode `mermaid` et c'est tout.\n\n## Flowchart example\n\t{{</*mermaid align=\"left\"*/>}}\n\tgraph LR;\n\t\tA[Bords droits] -->|Lien texte| B(Bords arondis)\n    \tB --> C{Décision}\n    \tC -->|Un| D[Résultat un]\n    \tC -->|Deux| E[Résultat deux]\n    {{</* /mermaid */>}}\n\nrenders as\n\n{{<mermaid align=\"left\">}}\ngraph LR;\n\tA[Bords droits] -->|Lien texte| B(Bords arondis)\n\tB --> C{Décision}\n\tC -->|Un| D[Résultat un]\n\tC -->|Deux| E[Résultat deux]\n{{< /mermaid >}}\n\n## Sequence example\n\n\t{{</*mermaid*/>}}\n\tsequenceDiagram\n\t    participant Alice\n\t    participant Bob\n\t    Alice->>John: Salut John, comment vas-tu?\n\t    loop Vérification\n\t        John->John: Se bat contre l'hyponcodrie.\n\t    end\n\t    Note right of John: Les pensées rationnelles<br/>prédominent...\n\t    John-->Alice: Super!\n\t    John->Bob: Et toi?\n\t    Bob-->John: Au top!\n\t{{</* /mermaid */>}}\n\nrenders as\n\n{{<mermaid>}}\nsequenceDiagram\n\tparticipant Alice\n\tparticipant Bob\n\tAlice->>John: Salut John, comment vas-tu?\n\tloop Vérification\n\t\tJohn->John: Se bat contre l'hyponcodrie.\n\tend\n\tNote right of John: Les pensées rationnelles<br/>prédominent...\n\tJohn-->Alice: Super!\n\tJohn->Bob: Et toi?\n\tBob-->John: Au top!\n{{< /mermaid >}}\n\n## GANTT Example\n\n\t{{</*mermaid*/>}}\n\tgantt\n\t        dateFormat  YYYY-MM-DD\n\t        title Ajout de la fonctionnalité de GANTT à Mermaid\n\t        section Une section\n\t        Tâche complétée            :done,    des1, 2014-01-06,2014-01-08\n\t        Tâche en cours             :active,  des2, 2014-01-09, 3d\n\t        Future tâche               :         des3, after des2, 5d\n\t        Future tâche 2             :         des4, after des3, 5d\n\t        section Tâches critiques\n\t        Tâche complétée dans le chemin critique :crit, done, 2014-01-06,24h\n\t        Implémenter le parser et jison          :crit, done, after des1, 2d\n\t        Créer des tests pour le parser          :crit, active, 3d\n\t        Future tâche dans le chemin critique    :crit, 5d\n\t        Créer des tests pour le renderer        :2d\n\t        Ajout à Mermaid                      \t:1d\n\t{{</* /mermaid */>}}\n\n\nrender as\n\n{{<mermaid>}}\ngantt\n\t\tdateFormat  YYYY-MM-DD\n\t\ttitle Ajout de la fonctionnalité de GANTT à Mermaid\n\t\tsection Une section\n\t\tTâche complétée            :done,    des1, 2014-01-06,2014-01-08\n\t\tTâche en cours             :active,  des2, 2014-01-09, 3d\n\t\tFuture tâche               :         des3, after des2, 5d\n\t\tFuture tâche 2             :         des4, after des3, 5d\n\t\tsection Tâches critiques\n\t\tTâche complétée dans le chemin critique :crit, done, 2014-01-06,24h\n\t\tImplémenter le parser et jison          :crit, done, after des1, 2d\n\t\tCréer des tests pour le parser             :crit, active, 3d\n\t\tFuture tâche dans le chemin critique        :crit, 5d\n\t\tCréer des tests pour le renderer           :2d\n\t\tAjout à Mermaid                      :1d\n{{</mermaid>}}\n\n\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/notice.en.md",
    "content": "---\ntitle: Notice\ndescription : \"Disclaimers to help you structure your page\"\n---\n\nThe notice shortcode shows 4 types of disclaimers to help you structure your page.\n\n### Note\n\n```\n{{%/* notice note */%}}\nA notice disclaimer\n{{%/* /notice */%}}\n```\n\nrenders as\n\n{{% notice note %}}\nA notice disclaimer\n{{% /notice %}}\n\n### Info\n\n```\n{{%/* notice info */%}}\nAn information disclaimer\n{{%/* /notice */%}}\n```\n\nrenders as\n\n{{% notice info %}}\nAn information disclaimer\n{{% /notice %}}\n\n### Tip\n\n```\n{{%/* notice tip */%}}\nA tip disclaimer\n{{%/* /notice */%}}\n```\n\nrenders as\n\n{{% notice tip %}}\nA tip disclaimer\n{{% /notice %}}\n\n### Warning\n\n```\n{{%/* notice warning */%}}\nAn warning disclaimer\n{{%/* /notice */%}}\n```\n\nrenders as\n\n{{% notice warning %}}\nA warning disclaimer\n{{% /notice %}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/notice.fr.md",
    "content": "---\ntitle: Notice\ndescription : \"Message pour vous aider à structurer votre contenu\"\n---\n\nLe shortcode *Notice* permet d'afficher 4 types de message pour vous aider à structurer votre contenu.\n\n### Note\n\n```\n{{%/* notice note */%}}\nUne notice de type *note*\n{{%/* /notice */%}}\n```\n\ns'affiche comme\n\n{{% notice note %}}\nUne notice de type *note*\n{{% /notice %}}\n\n### Info\n\n```\n{{%/* notice info */%}}\nUne notice de type *info*\n{{%/* /notice */%}}\n```\n\ns'affiche comme\n\n{{% notice info %}}\nUne notice de type *info*\n{{% /notice %}}\n\n### Tip\n\n```\n{{%/* notice tip */%}}\nUne notice de type *tip*\n{{%/* /notice */%}}\n```\n\ns'affiche comme\n\n{{% notice tip %}}\nUne notice de type *tip*\n{{% /notice %}}\n\n### Warning\n\n```\n{{%/* notice warning */%}}\nUne notice de type *warning*\n{{%/* /notice */%}}\n```\n\ns'affiche comme\n\n{{% notice warning %}}\nUne notice de type *warning*\n{{% /notice %}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/siteparam.en.md",
    "content": "---\ntitle: Site param\ndescription : \"Get value of site params variables in your page.\"\n---\n\n`siteparam` shortcode is used to help you print values of site params. \n\nFor instance, in this current site, the `editURL` variable is used in `config.toml`\n\n```toml\n[params]\n  editURL = \"https://github.com/matcornic/hugo-theme-learn/edit/master/exampleSite/content/\"\n```\n\nUse the `siteparam` shortcode to display its value.\n\n```\n`editURL` Value : {{%/* siteparam \"editURL\" */%}}\n```\n\nis displayed as\n\n`editURL` Value : {{% siteparam \"editURL\" %}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/shortcodes/siteparam.fr.md",
    "content": "---\ntitle: Site param\ndescription : \"Afficher la valeur d'un paramètre global du site dans votre page\"\n---\n\nLes shortcode `siteparam` est utilisé pour vous aider à afficher des valeurs provenant des paramètres globaux du site. \n\nPar exemple, dans ce site, le paramètre `editURL`  est utilisé dans le fichier `config.toml`\n\n```toml\n[params]\n  editURL = \"https://github.com/matcornic/hugo-theme-learn/edit/master/exampleSite/content/\"\n```\n\nUtilisez le shortcode `siteparam` pour affichier sa valeur.\n\n```\nValeur de `editURL` : {{%/* siteparam \"editURL\" */%}}\n```\n\ns'affiche comme\n\nValeur de `editURL` : {{% siteparam \"editURL\" %}}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/showcase.en.md",
    "content": "---\ntitle: Showcase\ndisableToc: true\n---\n\n#### [TAT](https://ovh.github.io/tat/overview/) by OVH\n![TAT image](/images/showcase/tat.png?width=50pc)\n\n\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/content/showcase.fr.md",
    "content": "---\ntitle: Vitrine\ndisableToc: true\nslug: vitrine\n---\n\n#### [TAT](https://ovh.github.io/tat/overview/) par OVH\n![TAT image](/images/showcase/tat.png?width=50pc)\n\n\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/layouts/partials/custom-footer.html",
    "content": "<script>\n  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');\n\n  ga('create', 'UA-105947713-1', 'auto');\n  ga('send', 'pageview');\n\n</script>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/layouts/partials/logo.html",
    "content": "<a id=\"logo\" href=\"/\">\n\n<svg id=\"grav-logo\" version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n\twidth=\"100%\" height=\"100%\"  viewBox=\"0 0 285.1 69.9\" xml:space=\"preserve\">\n<g>\n\t<path d=\"M35,0c9.6,0,17.9,3.4,24.7,10.3c6.8,6.8,10.3,15,10.3,24.7c0,9.7-3.4,17.9-10.3,24.7c-6.8,6.8-15,10.3-24.7,10.3\n\t\tc-9.7,0-17.9-3.4-24.7-10.3C3.4,52.8,0,44.6,0,34.9c0-9.6,3.4-17.9,10.3-24.7C17.1,3.4,25.3,0,35,0z M22.3,63.7\n\t\tc0.3-7.4,0.3-14.7,0-22.1c-2.1-0.4-4-0.4-5.9,0c-0.2,0.8-0.2,2.5-0.1,4.9c0.1,2.3,0,3.9-0.3,4.8c-1.7-0.6-2.7-2.1-3.1-4.6\n\t\tc-0.1-0.7-0.1-3.3-0.1-8c0-14.5-0.1-23-0.3-25.6c-3.6,4.1-5.6,7-5.9,8.5v10.9c0,4.5,0.1,8.1,0.2,10.9c0,0.4,0,1.3-0.1,2.8\n\t\tc-0.1,1.2,0,2.1,0.1,2.6c0.1,0.6,1.1,2.1,2.8,4.7C13.2,58.7,17.5,62.2,22.3,63.7z M44.6,65.4c0.3-5,0.2-12.9-0.1-23.6\n\t\tc-2.1-0.3-4.1-0.3-5.9,0c-0.2,2-0.2,5.1-0.1,9.5c0.1,4.3,0,7.5-0.1,9.5c-2.9,0.4-5,0.3-6.2-0.1c-0.2-5.6-0.2-15.2-0.1-28.7\n\t\tc0.1-12.4,0-21.8-0.3-28.3c-2.4,0.1-4.3,0.6-5.7,1.3c-0.1,7.7-0.2,17.7-0.1,30.1c0,16.5,0,26.6,0,30.3c2.3,1.1,5.4,1.7,9.4,1.7\n\t\tC38.9,66.9,42.1,66.4,44.6,65.4z M48.1,64.1c9.7-4.6,15.7-12,18-22.2c-1.8-0.2-3.8-0.3-6.1-0.3c-1.6,3.9-2.6,6.3-3.2,7.2\n\t\tc-1.1,1.7-2,2.5-2.7,2.5C54,46,54,39.1,54,30.5c0-11.5,0-18.4,0-20.9c-1.4-1.4-3.3-2.5-5.7-3.4C48.1,6.3,48,6.4,48,6.7\n\t\tc0,3.5,0,13.1,0,28.8C47.9,47.2,48,56.8,48.1,64.1z\"/>\n</g>\n<g>\n\t<path d=\"M116.6,51.3h-29c-0.5,0-0.9-0.1-1.3-0.2c-0.4-0.2-0.7-0.4-1-0.7c-0.3-0.3-0.5-0.6-0.7-1c-0.2-0.4-0.2-0.8-0.2-1.3V16.3h6.3\n\t\tV45h25.8V51.3z\"/>\n\t<path d=\"M154.8,51.3h-22.9c-0.9,0-1.8-0.2-2.9-0.5c-1-0.3-2-0.8-2.9-1.5c-0.9-0.7-1.6-1.6-2.2-2.8c-0.6-1.1-0.9-2.5-0.9-4.2V19.5\n\t\tc0-0.4,0.1-0.9,0.2-1.2c0.2-0.4,0.4-0.7,0.7-1c0.3-0.3,0.6-0.5,1-0.7c0.4-0.2,0.8-0.2,1.3-0.2h28.6v6.3h-25.4v19.8\n\t\tc0,0.8,0.2,1.5,0.7,1.9s1.1,0.7,1.9,0.7h22.9V51.3z M151.9,37h-20v-6.4h20V37z\"/>\n\t<path d=\"M197.3,51.3H191v-8.6h-22.3v8.6h-6.3V33.8c0-2.6,0.4-4.9,1.3-7.1s2.1-4,3.7-5.5c1.6-1.5,3.4-2.8,5.5-3.6\n\t\tc2.1-0.9,4.5-1.3,7-1.3h14.3c0.4,0,0.9,0.1,1.2,0.2c0.4,0.2,0.7,0.4,1,0.7s0.5,0.6,0.7,1c0.2,0.4,0.2,0.8,0.2,1.2V51.3z\n\t\t M168.7,36.4H191V22.6h-11.2c-0.2,0-0.6,0-1.2,0.1c-0.6,0.1-1.4,0.2-2.2,0.4c-0.8,0.2-1.7,0.6-2.6,1c-0.9,0.5-1.8,1.1-2.5,2\n\t\tc-0.8,0.8-1.4,1.9-1.9,3.1c-0.5,1.2-0.7,2.8-0.7,4.5V36.4z\"/>\n\t<path d=\"M241.7,28.1c0,1.4-0.2,2.7-0.5,3.9c-0.4,1.1-0.8,2.1-1.5,3c-0.6,0.9-1.3,1.6-2.1,2.2c-0.8,0.6-1.6,1.1-2.5,1.5\n\t\tc-0.9,0.4-1.8,0.7-2.6,0.9c-0.9,0.2-1.7,0.3-2.5,0.3l13.3,11.5h-9.8l-13.2-11.5h-4.6v-6.3H230c0.8-0.1,1.5-0.2,2.2-0.5\n\t\tc0.7-0.3,1.2-0.6,1.7-1.1c0.5-0.5,0.9-1,1.1-1.6c0.3-0.6,0.4-1.4,0.4-2.2v-4c0-0.4,0-0.6-0.1-0.8c-0.1-0.2-0.2-0.3-0.3-0.4\n\t\tc-0.1-0.1-0.3-0.1-0.4-0.2c-0.2,0-0.3,0-0.4,0h-20.9v28.7h-6.3V19.5c0-0.4,0.1-0.9,0.2-1.2c0.2-0.4,0.4-0.7,0.7-1\n\t\tc0.3-0.3,0.6-0.5,1-0.7c0.4-0.2,0.8-0.2,1.3-0.2H234c1.4,0,2.6,0.3,3.6,0.8s1.8,1.2,2.4,1.9c0.6,0.8,1,1.6,1.3,2.5\n\t\tc0.3,0.9,0.4,1.7,0.4,2.5V28.1z\"/>\n\t<path d=\"M285.1,48.6c0,0.5-0.1,0.9-0.3,1.3c-0.2,0.4-0.4,0.7-0.7,1c-0.3,0.3-0.6,0.5-1,0.7c-0.4,0.2-0.8,0.2-1.2,0.2\n\t\tc-0.4,0-0.8-0.1-1.2-0.2c-0.4-0.1-0.8-0.4-1.1-0.7l-23.2-24.2v24.7h-6.3V19c0-0.7,0.2-1.2,0.5-1.8c0.4-0.5,0.8-0.9,1.4-1.2\n\t\tc0.6-0.2,1.2-0.3,1.9-0.2s1.2,0.4,1.6,0.9l23.2,24.2V16.3h6.3V48.6z\"/>\n</g>\n</svg>\n\n</a>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/layouts/partials/menu-footer.html",
    "content": "<center>\n    <!-- Place this tag where you want the button to render. -->\n    <a class=\"github-button\" href=\"https://github.com/matcornic/hugo-theme-learn/archive/master.zip\" data-icon=\"octicon-cloud-download\" aria-label=\"Download matcornic/hugo-theme-learn on GitHub\">Download</a>\n\n    <!-- Place this tag where you want the button to render. -->\n    <a class=\"github-button\" href=\"https://github.com/matcornic/hugo-theme-learn\" data-icon=\"octicon-star\" data-show-count=\"true\" aria-label=\"Star matcornic/hugo-theme-learn on GitHub\">Star</a>\n\n    <!-- Place this tag where you want the button to render. -->\n    <a class=\"github-button\" href=\"https://github.com/matcornic/hugo-theme-learn/fork\" data-icon=\"octicon-repo-forked\" data-show-count=\"true\" aria-label=\"Fork matcornic/hugo-theme-learn on GitHub\">Fork</a>\n\n    <p>Built with <a href=\"https://github.com/matcornic/hugo-theme-learn\"><i class=\"fa fa-heart\"></i></a> from <a href=\"http://getgrav.org\">Grav</a> and <a href=\"http://gohugo.io/\">Hugo</a></p>\n</center>\n<!-- Place this tag in your head or just before your close body tag. -->\n<script async defer src=\"https://buttons.github.io/buttons.js\"></script>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/layouts/shortcodes/ghcontributors.html",
    "content": "<style type=\"text/css\">\n.ghContributors{\ndisplay:flex;\nflex-flow:  wrap;\nalign-content: flex-start\n}\n\n.ghContributors > div{\nwidth: 50% ;\ndisplay: inline-flex;\nmargin-bottom: 5px;\n}\n.ghContributors > div label{\npadding-left: 4px ;\n}\n.ghContributors > div span{\nfont-size: x-small;\npadding-left: 4px ;\n}\n\n</style>\n<div class=\"ghContributors\">\n  {{ $url := .Get 0 }}\n  {{ range getJSON $url }}\n  <div>\n    <img src=\"{{.avatar_url}}\" class=\"inline\" width=\"32\" height=\"32\" style=\"height: 32px;height: 32px;margin-bottom:.25em; vertical-align:middle; \">\n    <label><a href=\"{{.html_url}}\">@{{.login}}</a></label>\n    <span class=\"contributions\">{{.contributions}} commits</span>\n  </div>\n  {{ end }}\n</div>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/exampleSite/static/css/theme-mine.css",
    "content": "\n:root{\n    \n    --MAIN-TEXT-color:#323232; /* Color of text by default */\n    --MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */\n    --MAIN-LINK-color:#599a3e; /* Color of links */\n    --MAIN-LINK-HOVER-color:#3f6d2c; /* Color of hovered links */\n    --MAIN-ANCHOR-color: #599a3e; /* color of anchors on titles */\n\n    --MENU-HEADER-BG-color:#74b559; /* Background color of menu header */\n    --MENU-HEADER-BORDER-color:#9cd484; /*Color of menu header border */ \n    \n    --MENU-SEARCH-BG-color:#599a3e; /* Search field background color (by default borders + icons) */\n    --MENU-SEARCH-BOX-color: #84c767; /* Override search field border color */\n    --MENU-SEARCH-BOX-ICONS-color: #c7f7c4; /* Override search field icons color */\n\n    --MENU-SECTIONS-ACTIVE-BG-color:#1b211c; /* Background color of the active section and its childs */\n    --MENU-SECTIONS-BG-color:#222723; /* Background color of other sections */\n    --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */\n    --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6;  /* Color of links in menu, when hovered */\n    --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */\n    --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */\n\n    --MENU-VISITED-color: #599a3e; /* Color of 'page visited' icons in menu */\n    --MENU-SECTION-HR-color: #18211c; /* Color of <hr> separator in menu */\n    \n}\n\nbody {\n    color: var(--MAIN-TEXT-color) !important;\n}\n\ntextarea:focus, input[type=\"email\"]:focus, input[type=\"number\"]:focus, input[type=\"password\"]:focus, input[type=\"search\"]:focus, input[type=\"tel\"]:focus, input[type=\"text\"]:focus, input[type=\"url\"]:focus, input[type=\"color\"]:focus, input[type=\"date\"]:focus, input[type=\"datetime\"]:focus, input[type=\"datetime-local\"]:focus, input[type=\"month\"]:focus, input[type=\"time\"]:focus, input[type=\"week\"]:focus, select[multiple=multiple]:focus {\n    border-color: none;\n    box-shadow: none;\n}\n\nh2, h3, h4, h5 {\n    color: var(--MAIN-TITLES-TEXT-color) !important;\n}\n\na {\n    color: var(--MAIN-LINK-color);\n}\n\n.anchor {\n    color: var(--MAIN-ANCHOR-color);\n}\n\na:hover {\n    color: var(--MAIN-LINK-HOVER-color);\n}\n\n#sidebar ul li.visited > a .read-icon {\n\tcolor: var(--MENU-VISITED-color);\n}\n\n#body a.highlight:after {\n    display: block;\n    content: \"\";\n    height: 1px;\n    width: 0%;\n    -webkit-transition: width 0.5s ease;\n    -moz-transition: width 0.5s ease;\n    -ms-transition: width 0.5s ease;\n    transition: width 0.5s ease;\n    background-color: var(--MAIN-LINK-HOVER-color);\n}\n#sidebar {\n\tbackground-color: var(--MENU-SECTIONS-BG-color);\n}\n#sidebar #header-wrapper {\n    background: var(--MENU-HEADER-BG-color);\n    color: var(--MENU-SEARCH-BOX-color);\n    border-color: var(--MENU-HEADER-BORDER-color);\n}\n#sidebar .searchbox {\n\tborder-color: var(--MENU-SEARCH-BOX-color);\n    background: var(--MENU-SEARCH-BG-color);\n}\n#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {\n    background: var(--MENU-SECTIONS-ACTIVE-BG-color);\n}\n#sidebar .searchbox * {\n    color: var(--MENU-SEARCH-BOX-ICONS-color);\n}\n\n#sidebar a {\n    color: var(--MENU-SECTIONS-LINK-color);\n}\n\n#sidebar a:hover {\n    color: var(--MENU-SECTIONS-LINK-HOVER-color);\n}\n\n#sidebar ul li.active > a {\n    background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);\n    color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;\n}\n\n#sidebar hr {\n    border-color: var(--MENU-SECTION-HR-color);\n}\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/i18n/en.toml",
    "content": "[Search-placeholder]\nother = \"Search...\"\n\n[Clear-History]\nother = \"Clear History\"\n\n[Attachments-label]\nother = \"Attachments\"\n\n[title-404]\nother = \"Error\"\n\n[message-404]\nother = \"Woops. Looks like this page doesn't exist ¯\\\\_(ツ)_/¯.\"\n\n[Go-to-homepage]\nother = \"Go to homepage\"\n\n[Edit-this-page]\nother = \"Edit this page\"\n\n[Shortcuts-Title]\nother = \"More\"\n\n[Expand-title]\nother = \"Expand me...\""
  },
  {
    "path": "docs/themes/hugo-theme-learn/i18n/es.toml",
    "content": "[Search-placeholder]\nother = \"Buscar...\"\n\n[Clear-History]\nother = \"Borrar Historial\"\n\n[Attachments-label]\nother = \"Adjuntos\"\n\n[title-404]\nother = \"Error\"\n\n[message-404]\nother = \"Ups. Parece que la página no existe ¯\\\\_(ツ)_/¯.\"\n\n[Go-to-homepage]\nother = \"Ir al inicio\"\n\n[Edit-this-page]\nother = \"Editar esta página\"\n\n[Shortcuts-Title]\nother = \"Más\"\n\n[Expand-title]\nother = \"Expandir...\"\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/i18n/fr.toml",
    "content": "[Search-placeholder]\nother = \"Rechercher...\"\n\n[Clear-History]\nother = \"Supprimer l'historique\"\n\n[Attachments-label]\nother = \"Pièces jointes\"\n\n[title-404]\nother = \"Erreur\"\n\n[message-404]\nother = \"Oups. On dirait que cette page n'existe pas ¯\\\\_(ツ)_/¯\"\n\n[Go-to-homepage]\nother = \"Vers la page d'accueil\"\n\n[Edit-this-page]\nother = \"Modifier la page\"\n\n[Shortcuts-Title]\nother = \"Aller plus loin\"\n\n[Expand-title]\nother = \"Déroulez-moi...\""
  },
  {
    "path": "docs/themes/hugo-theme-learn/i18n/pt.toml",
    "content": "[Search-placeholder]\nother = \"Procurar...\"\n\n[Clear-History]\nother = \"Limpar Histórico\"\n\n[Attachments-label]\nother = \"Anexos\"\n\n[title-404]\nother = \"Erro\"\n\n[message-404]\nother = \"Ops. Parece que a página não existe ¯\\\\_(ツ)_/¯.\"\n\n[Go-to-homepage]\nother = \"Ir para o início\"\n\n[Edit-this-page]\nother = \"Editar esta página\"\n\n[Shortcuts-Title]\nother = \"Mais\"\n\n[Expand-title]\nother = \"Expandir...\"\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/404.html",
    "content": "<!DOCTYPE html>\n<html lang=\"{{ .Page.Language | default \"en\" }}\" class=\"js csstransforms3d\">\n\n<head>\n  <meta charset=\"utf-8\"> {{ partial \"meta.html\" . }} {{ partial \"favicon.html\" . }} {{ .Scratch.Add \"title\" \"\" }}{{ if eq .Site.Data.titles .Title }}{{ .Scratch.Set \"title\" (index .Site.Data.titles .Title).title }}{{ else }}{{ .Scratch.Set \"title\" .Title}}{{end}}\n  <title>{{ .Scratch.Get \"title\" }}</title>\n  \n   {{ $assetBusting := not .Site.Params.disableAssetsBusting }}\n    <link href=\"{{\"css/nucleus.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/font-awesome.min.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/hybrid.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/featherlight.min.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/perfect-scrollbar.min.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/horsey.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/theme.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/hugo-theme.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    {{with .Site.Params.themeVariant}}\n      <link href=\"{{(printf \"css/theme-%s.css\" .) | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    {{end}}\n<style type=\"text/css\">\n    :root #header + #content > #left > #rlblock_left {\n      display: none !important;\n    }\n\n    p,\n    li,\n    ul {\n      text-align: center\n    }\n\n    ul {\n      list-style-type: none;\n    }\n</style>\n{{ partial \"custom-header.html\" . }}\n</head>\n\n<body>\n\n  <body class=\"\" data-url=\"/\">\n\n    <section id=\"body\" style=\"margin-left:0px;\">\n      <div id=\"overlay\"></div>\n      <div id=\"chapter\">\n        <div id=\"body-inner\">\n          <h1>{{T \"title-404\"}}</h1>\n          <p>\n          </p>\n          <p>{{T \"message-404\"}}</p>\n          <p></p>\n          <p><a href='{{ \"\" | relLangURL }}'>{{T \"Go-to-homepage\"}}</a></p>\n          <p><img src='{{ \"/images/gopher-404.jpg\" | relURL }}' style=\"width:50%\"></img></p>\n        </div>\n      </div>\n\n    </section>\n  </body>\n\n</html>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/_default/list.html",
    "content": "{{ partial \"header.html\" . }}\n\n{{ .TableOfContents }}\n\n{{ .Content }}\n\n<footer class=\" footline\" >\n\t{{with .Params.LastModifierDisplayName}}\n\t    <i class='fa fa-user'></i> <a href=\"mailto:{{ $.Params.LastModifierEmail }}\">{{ . }}</a> {{with $.Date}} <i class='fa fa-calendar'></i> {{ .Format \"02/01/2006\" }}{{end}}\n\t    </div>\n\t{{end}}\n</footer>\n\n{{ partial \"footer.html\" . }}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/_default/single.html",
    "content": "{{ partial \"header.html\" . }}\n\n{{ .TableOfContents }}\n\n{{ .Content }}\n\n<footer class=\" footline\" >\n\t{{with .Params.LastModifierDisplayName}}\n\t    <i class='fa fa-user'></i> <a href=\"mailto:{{ $.Params.LastModifierEmail }}\">{{ . }}</a> {{with $.Date}} <i class='fa fa-calendar'></i> {{ .Format \"02/01/2006\" }}{{end}}\n\t    </div>\n\t{{end}}\n</footer>\n\n\n{{ partial \"footer.html\" . }}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/index.html",
    "content": "{{ partial \"header.html\" . }}\n<span id=\"sidebar-toggle-span\">\n<a href=\"#\" id=\"sidebar-toggle\" data-sidebar-toggle=\"\"><i class=\"fa fa-bars\"></i> navigation</a>\n</span>\n\n{{if .Site.Home.Content }} \n{{.Site.Home.Content}}\t\n{{else}}           \n\t{{if eq .Site.Language.Lang \"fr\"}}\n\t\t<h1>Personaliser la page d'accueil</h1>\n\t\t<p>\n\t\t  Le site fonctionne. Ne pas oublier de personaliser cette page avec votre propre contenu. 3 manières de faire :\n\t\t</p>\n\t\t<ul>\n\t\t\t<li><b>1. </b> Créer un fichier _index.md dans le dossier <b>content</b> et le remplir de Markdown</li>\n\t\t\t<li><b>2. </b> Créer un fichier index.html dans le dossier <b>static</b> et le remplir de code HTML</li>\n\t\t  <li><b>3. </b> Configurer le serveur http pour rediriger automatiquement la homepage vers la page de votre choix dans le site</li>\n\t\t</ul>\n\t{{else}}\n\t\t<h1>Customize your own home page</h1>\n\t\t<p>\n\t\t  The site is working. Don't forget to customize this homepage with your own. You typically have 3 choices :\n\t\t</p>\n\t\t<ul>\n\t\t\t<li><b>1. </b> Create an _index.md document in <b>content</b> folder and fill it with Markdown content</li>\n\t\t\t<li><b>2. </b> Create an <b>index.html</b> file in the <b>static</b> folder and fill the file with HTML content</li>\n\t\t  <li><b>3. </b> Configure your server to automatically redirect home page to one your documentation page</li>\n\t\t</ul>\n\t{{end}}\n{{ end }}  \n{{ partial \"footer.html\" . }}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/index.json",
    "content": "[{{ range $index, $page := .Site.Pages }}\n{{- if ne $page.Type \"json\" -}}\n{{- if and $index (gt $index 0) -}},{{- end }}\n{\n\t\"uri\": \"{{ $page.Permalink }}\",\n\t\"title\": \"{{ htmlEscape $page.Title}}\",\n\t\"tags\": [{{ range $tindex, $tag := $page.Params.tags }}{{ if $tindex }}, {{ end }}\"{{ $tag| htmlEscape }}\"{{ end }}],\n\t\"description\": \"{{ htmlEscape .Description}}\",\n\t\"content\": {{$page.Plain | jsonify}}\n}\n{{- end -}}\n{{- end -}}]"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/change-theme.html",
    "content": "<div class=\"change-theme\">\n    <div class=\"wrap\">\n        {{ if eq .Lang \"en\"}}\n        <span data-item=\"retro\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            Retro\n        </span>\n        <span data-item=\"eyehelp\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            Eye care\n        </span>\n        <span data-item=\"haitian\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            Haitian\n        </span>\n        <span data-item=\"deep\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            Deep\n        </span>\n        <span data-item=\"dark\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            Dark\n        </span>\n        <span class=\"active\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            Default\n        </span>\n        {{ else }}\n        <span data-item=\"retro\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            复古\n        </span>\n        <span data-item=\"eyehelp\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            护眼\n        </span>\n        <span data-item=\"haitian\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            海天\n        </span>\n        <span data-item=\"deep\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            深邃\n        </span>\n        <span data-item=\"dark\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            暗黑\n        </span>\n        <span class=\"active\">\n            <svg t=\"1649761460834\" class=\"icon\" viewBox=\"0 0 1243 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2052\" width=\"16\" height=\"16\"><path d=\"M755.093336 61.436797a511.973304 511.973304 0 1 0 207.495466 693.650688l-99.615377-53.757197a398.827204 398.827204 0 1 1-161.637286-540.351253l53.757197-99.615378z\" fill=\"#ffffff\" p-id=\"2053\"></path><path d=\"M1204.971593 188.84501L534.652259 736.217612l-285.242269-364.086159 86.304071-67.653615 216.199012 275.953611 583.649567-476.574007 69.335813 84.987568z\" fill=\"#ffffff\" p-id=\"2054\"></path></svg>\n            默认\n        </span>\n        {{ end }}\n    </div>\n</div>\n\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/custom-comments.html",
    "content": "<!-- import your comments system \n{{ template \"_internal/disqus.html\" . }}\n-->\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/custom-footer.html",
    "content": "<!-- Partial intended to be overwritten with tags loaded at the end of the page loading (usually for Javascript) \n<script>\n    console.log(\"running some javascript\");\n</script>\n-->\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/custom-header.html",
    "content": "<!-- Partial intended to be overwritten to add custom headers, like CSS or any other info\n<style type=\"text/css\">\n    /* Custom css */\n</style>\n-->\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/favicon.html",
    "content": "<link rel=\"shortcut icon\" href=\"{{\"images/favicon.png\" | relURL}}\" type=\"image/x-icon\" />\n<link rel=\"icon\" href=\"{{\"images/favicon.png\" | relURL}}\" type=\"image/x-icon\" />\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/footer.html",
    "content": "        {{ if .Params.chapter }}\n            </div> <!-- end chapter-->\n        {{ end }}\n        </div> \n        {{ partial \"custom-comments.html\" . }}\n      </div>\n\n    <div id=\"navigation\">\n        <!-- Next prev page -->\n        {{ $currentNode := . }}\n        \n        {{ template \"menu-nextprev\" dict \"menu\" .Site.Home \"currentnode\" $currentNode }}\n        \n        {{ define \"menu-nextprev\" }}\n            {{$currentNode := .currentnode }}\n            {{ if ne .menu.Params.hidden true}}\n                {{if hasPrefix $currentNode.URL .menu.URL }}\n                    {{ $currentNode.Scratch.Set \"NextPageOK\" \"OK\" }}\n                    {{ $currentNode.Scratch.Set \"prevPage\" ($currentNode.Scratch.Get \"prevPageTmp\") }}\n                {{else}}\n                    {{if eq ($currentNode.Scratch.Get \"NextPageOK\") \"OK\"}}\n                        {{ $currentNode.Scratch.Set \"NextPageOK\" nil }}\n                        {{ $currentNode.Scratch.Set \"nextPage\" .menu }}\n                    {{end}}\n                {{end}}\n                {{ $currentNode.Scratch.Set \"prevPageTmp\" .menu }}\n\n                    {{ $currentNode.Scratch.Set \"pages\" .menu.Pages }}\n                    {{ if .menu.IsHome}}\n                        {{ $currentNode.Scratch.Set \"pages\" .menu.Sections }}\n                    {{ else if .menu.Sections}}\n                        {{ $currentNode.Scratch.Set \"pages\" (.menu.Pages | union .menu.Sections) }}\n                    {{end}}\n                    {{ $pages := ($currentNode.Scratch.Get \"pages\") }}\n\n                    {{ range $pages.ByWeight  }}\n                        {{ template \"menu-nextprev\" dict \"menu\" . \"currentnode\" $currentNode }}\n                    {{end}}\n            {{ end }}\n        {{ end }}\n\n\n        {{with ($.Scratch.Get \"prevPage\")}}\n        {{ if eq .Lang \"en\"}}\n            <a class=\"nav nav-prev\" href=\"{{.URL}}\" title=\"{{.Title}}\"> <i class=\"fa fa-long-arrow-left fa-lg\"></i> Previous</a>\n        {{ else }} \n            <a class=\"nav nav-prev\" href=\"{{.URL}}\" title=\"{{.Title}}\"> <i class=\"fa fa-long-arrow-left fa-lg\"></i> 上一篇</a>\n        {{end}}\n        {{end}}\n        {{with ($.Scratch.Get \"nextPage\")}}\n        {{ if eq .Lang \"en\"}}\n            <a class=\"nav nav-next\" href=\"{{.URL}}\" title=\"{{.Title}}\" style=\"margin-right: 0px;\">Next<i class=\"fa fa-long-arrow-right fa-lg\"></i></a>\n        {{ else }} \n            <a class=\"nav nav-next\" href=\"{{.URL}}\" title=\"{{.Title}}\" style=\"margin-right: 0px;\">下一篇 <i class=\"fa fa-long-arrow-right fa-lg\"></i></a>\n        {{end}}\n        {{end}}\n    </div>\n\n    </section>\n</div>\n    <div style=\"left: -1000px; overflow: scroll; position: absolute; top: -1000px; border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;\">\n      <div style=\"border: none; box-sizing: content-box; height: 200px; margin: 0px; padding: 0px; width: 200px;\"></div>\n    </div>\n    <script src=\"{{\"js/clipboard.min.js\" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}\"></script>\n    <script src=\"{{\"js/perfect-scrollbar.min.js\" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}\"></script>\n    <script src=\"{{\"js/perfect-scrollbar.jquery.min.js\" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}\"></script>\n    <script src=\"{{\"js/jquery.sticky.js\" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}\"></script>\n    <script src=\"{{\"js/featherlight.min.js\" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}\"></script>\n    <script src=\"{{\"js/html5shiv-printshiv.min.js\" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}\"></script>\n    <script src=\"{{\"js/highlight.pack.js\" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}\"></script>\n    <script>hljs.initHighlightingOnLoad();</script>\n    <script src=\"{{\"js/modernizr.custom.71422.js\" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}\"></script>\n    <script src=\"{{\"js/learn.js\" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}\"></script>\n    <script src=\"{{\"js/hugo-learn.js\" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}\"></script>\n\n    {{ partial \"custom-footer.html\" . }}\n  </body>\n</html>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/header.html",
    "content": "<!DOCTYPE html>\n<html lang=\"{{ .Page.Language | default \"en\" }}\" class=\"js csstransforms3d\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no\">\n    {{ .Hugo.Generator }}\n    {{ partial \"meta.html\" . }}\n    {{ partial \"favicon.html\" . }}\n    <title>{{ .Title }} :: {{ .Site.Title }}</title>\n    \n    {{ $assetBusting := not .Site.Params.disableAssetsBusting }}\n    <link href=\"{{\"css/nucleus.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/font-awesome.min.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/hybrid.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/featherlight.min.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/perfect-scrollbar.min.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/auto-complete.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/theme.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    <link href=\"{{\"css/hugo-theme.css\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    {{with .Site.Params.themeVariant}}\n      <link href=\"{{(printf \"css/theme-%s.css\" .) | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\" rel=\"stylesheet\">\n    {{end}}\n\n    <script src=\"{{\"js/jquery-2.x.min.js\"| relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\"></script>\n    <!-- baidu Analytics -->\n    <script>\n      var _hmt = _hmt || [];\n      (function() {\n        var hm = document.createElement(\"script\");\n        hm.src = \"https://hm.baidu.com/hm.js?d5a1dc8dcf63a64ee55b80de01c7fb1a\";\n        var s = document.getElementsByTagName(\"script\")[0]; \n        s.parentNode.insertBefore(hm, s);\n      })();   \n    </script>\n    <!-- Global site tag (gtag.js) - Google Analytics -->\n    <script async src=\"https://www.googletagmanager.com/gtag/js?id=G-HETCF66YL0\"></script>\n    <script>\n      window.dataLayer = window.dataLayer || [];\n      function gtag(){window.dataLayer.push(arguments);}\n      gtag('js', new Date());\n\n      gtag('config', 'G-HETCF66YL0');\n    </script>\n\n    <style type=\"text/css\">\n      :root #header + #content > #left > #rlblock_left{ \n          display:none !important;\n      }\n      {{ if .Site.Params.disableInlineCopyToClipBoard }}\n        :not(pre) > code + span.copy-to-clipboard {\n            display: none;\n        }\n      {{ end }}\n      \n      {{ if .Params.extracss }}\n        #TableOfContents {\n          display: none;\n        }\n        h2, #latest-releases {\n          color:#272822; \n          padding:0.3rem; \n          padding-left: 0px; \n          border-radius:2px; \n          letter-spacing:-1px; \n          font-size:1.3rem; \n          margin: 2rem 0 1rem 0; \n          font-weight:bold;\n        }\n        #latest-releases {\n          margin: 0rem 0 1rem 0;\n        }\n        h5 {\n          border: 0px solid #405871; \n          background-color: rgba(110, 141, 173, 0.87); \n          color:rgba(255, 255, 255, 0.99); \n          padding:0.3rem; \n          padding-left: 12px; \n          border-radius:5px; \n          font-size: 14.5px;\n          letter-spacing:0.1px;\n        }\n        pre {\n          margin: 1rem 0 1rem 0;\n        }\n      {{ end }}\n    </style>\n    {{ partial \"custom-header.html\" . }}\n  </head>\n  <body class=\"\" data-url=\"{{ .RelPermalink }}\">\n    {{ partial \"change-theme.html\" . }}\n    <header>\n      <div class=\"wrap\">\n        {{ partial \"logo.html\" . }}\n        \n        {{ partial \"language.html\" . }}\n      </div>\n    </header>\n    <div class=\"wrap\">\n    {{ partial \"menu.html\" . }}\n        <section id=\"body\">\n        <div id=\"overlay\"></div>\n        <div class=\"padding highlightable\">\n              {{if not .IsHome}}\n              <div>\n                <div id=\"top-bar\">\n                {{ if and (or .IsPage .IsSection) .Site.Params.editURL }}\n                  {{ $File := .File }}\n                  {{ $Site := .Site }}\n                  {{with $File.Path }}\n                  <div id=\"top-github-link\">\n                    <a class=\"github-link\" title='{{T \"Edit-this-page\"}}' href=\"{{ $Site.Params.editURL }}{{ replace $File.Dir \"\\\\\" \"/\" }}{{ $File.LogicalName }}\" target=\"blank\">\n                      <i class=\"fa fa-code-fork\"></i>\n                      <span id=\"top-github-link-text\">{{T \"Edit-this-page\"}}</span>\n                    </a>\n                  </div>\n                  {{ end }}\n                {{ end }}\n                {{$toc := (and (not .Params.disableToc) (not .Params.chapter))}}\n                <div id=\"breadcrumbs\" itemscope=\"\" itemtype=\"http://data-vocabulary.org/Breadcrumb\">\n                    <span id=\"sidebar-toggle-span\">\n                        <a href=\"#\" id=\"sidebar-toggle\" data-sidebar-toggle=\"\">\n                          <i class=\"fa fa-bars\"></i>\n                        </a>\n                    </span>\n                  {{ if $toc }}\n                  <span id=\"toc-menu\"><i class=\"fa fa-list-alt\"></i></span>\n                  {{ end }}\n                  <span class=\"links\">\n                    {{ template \"breadcrumb\" dict \"page\" . \"value\" .Title }}   \n                  </span>\n                </div>\n                {{ if $toc }}\n                    {{ partial \"toc.html\" . }}\n                {{ end }}\n              </div>\n            </div>\n            {{ end }}\n\n        {{ if .Params.chapter }}\n          <div id=\"chapter\">\n        {{ end }}\n        <div id=\"body-inner\">\n          {{if and (not .IsHome) (not .Params.chapter) }}\n            <h1>{{.Title}}</h1>\n          {{end}}\n\n        {{define \"breadcrumb\"}}\n          {{$parent := .page.Parent }}\n          {{ if $parent }}\n            {{ $value := (printf \"<a href='%s'>%s</a> > %s\" $parent.URL $parent.Title .value) }}\n            {{ template \"breadcrumb\" dict \"page\" $parent \"value\" $value }} \n          {{else}}\n            {{.value|safeHTML}}\n          {{end}}\n        {{end}}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/language.html",
    "content": "{{ $currentNode := . }}\n        {{ $showvisitedlinks := .Site.Params.showVisitedLinks }}\n        {{ if or .Site.IsMultiLingual $showvisitedlinks }}\n        <section id=\"prefooter\">\n          <!-- <hr/> -->\n          <ul>\n          {{ if and .Site.IsMultiLingual (not .Site.Params.DisableLanguageSwitchingButton)}}\n            <li>\n              <a class=\"padding\">\n                <i class=\"fa fa-fw fa-language\"></i>\n              <div class=\"select-style\">\n                <select id=\"select-language\" onchange=\"location = this.value;\">\n              {{ $siteLanguages := .Site.Languages}}\n              {{ $pageLang := .Page.Lang}}\n              {{ range .Page.AllTranslations }}\n                  {{ $translation := .}}\n                  {{ range $siteLanguages }}\n                      {{ if eq $translation.Lang .Lang }}\n                        {{ $selected := false }}\n                        {{ if eq $pageLang .Lang}}\n                          <option id=\"{{ $translation.Language }}\" value=\"{{ $translation.URL }}\" selected>{{ .LanguageName }}</option>\n                        {{ else }}\n                          <option id=\"{{ $translation.Language }}\" value=\"{{ $translation.URL }}\">{{ .LanguageName }}</option>\n                        {{ end }}\n                      {{ end }}\n                  {{ end }}\n              {{ end }}\n            </select>\n            <svg t=\"1645437162166\" class=\"icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"2449\" width=\"32\" height=\"32\"><path d=\"M483.072 714.496l30.165333 30.208 415.957334-415.829333a42.837333 42.837333 0 0 0 0-60.288 42.538667 42.538667 0 0 0-60.330667-0.042667l-355.541333 355.413333-355.242667-355.413333a42.496 42.496 0 0 0-60.288 0 42.837333 42.837333 0 0 0-0.085333 60.330667l383.701333 383.872 1.706667 1.749333z\" fill=\"#3D3D3D\" p-id=\"2450\"></path></svg>\n            </div>\n            </a>\n            </li>\n          {{end}} \n          \n          {{ if $showvisitedlinks}}\n            <li><a class=\"padding\" href=\"#\" data-clear-history-toggle=\"\"><i class=\"fa fa-fw fa-history\"></i> {{T \"Clear-History\"}}</a></li>         \n          {{ end }}\n          </ul>\n        </section>\n        {{ end }}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/logo.html",
    "content": "<a id=\"logo\" href=\"http://getgrav.org\">\n  <svg id=\"grav-logo\" width=\"100%\" height=\"100%\" viewBox=\"0 0 504 140\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:space=\"preserve\" style=\"fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;\">\n    <path d=\"M235.832,71.564l-7.98,-0.001c-1.213,0.001 -2.197,0.987 -2.197,2.204l0,15.327l-0.158,0.132c-4.696,3.962 -10.634,6.14 -16.719,6.14c-14.356,0 -26.034,-11.68 -26.034,-26.037c0,-14.358 11.678,-26.035 26.034,-26.035c5.582,0 10.919,1.767 15.437,5.113c0.877,0.649 2.093,0.56 2.866,-0.211l5.69,-5.69c0.444,-0.442 0.675,-1.055 0.639,-1.681c-0.034,-0.627 -0.336,-1.206 -0.828,-1.597c-6.76,-5.363 -15.214,-8.314 -23.805,-8.314c-21.18,0 -38.414,17.233 -38.414,38.415c0,21.183 17.234,38.415 38.414,38.415c10.937,0 21.397,-4.705 28.698,-12.914c0.358,-0.403 0.556,-0.921 0.556,-1.46l0,-19.603c0,-1.217 -0.985,-2.203 -2.2,-2.203\"\n      style=\"fill:#000;fill-rule:nonzero;\"></path>\n    <path d=\"M502.794,34.445c-0.408,-0.616 -1.1,-0.989 -1.838,-0.989l-8.684,0c-0.879,0 -1.673,0.522 -2.022,1.329l-24.483,56.839l-24.92,-56.852c-0.352,-0.799 -1.142,-1.316 -2.012,-1.316l-8.713,0c-0.744,0 -1.44,0.373 -1.843,0.995c-0.408,0.623 -0.476,1.408 -0.174,2.09l30.186,68.858c0.352,0.799 1.143,1.317 2.017,1.317l10.992,0c0.879,0 1.673,-0.527 2.021,-1.329l29.655,-68.861c0.289,-0.68 0.222,-1.461 -0.182,-2.081\"\n      style=\"fill:#000;fill-rule:nonzero;\"></path>\n    <path d=\"M388.683,34.772c-0.353,-0.798 -1.142,-1.316 -2.017,-1.316l-10.988,0c-0.879,0 -1.673,0.522 -2.021,1.329l-29.655,68.861c-0.294,0.675 -0.226,1.46 0.182,2.077c0.407,0.619 1.096,0.993 1.838,0.993l8.684,0c0.879,0 1.673,-0.526 2.022,-1.329l24.478,-56.842l24.92,56.854c0.353,0.798 1.143,1.317 2.013,1.317l8.717,0c0.744,0 1.44,-0.374 1.843,-0.993c0.408,-0.624 0.471,-1.41 0.174,-2.094l-30.19,-68.857Z\"\n      style=\"fill:#000;fill-rule:nonzero;\"></path>\n    <path d=\"M309.196,81.525l0.476,-0.229c8.675,-4.191 14.279,-13.087 14.279,-22.667c0,-13.881 -11.295,-25.174 -25.176,-25.174l-31.863,0c-1.214,0 -2.199,0.988 -2.199,2.202l0,68.855c0,1.219 0.985,2.204 2.199,2.204l7.979,0c1.214,0 2.2,-0.985 2.2,-2.204l0,-58.679l21.684,0c7.059,0 12.799,5.739 12.799,12.796c0,5.885 -3.996,10.989 -9.728,12.408c-1.032,0.261 -2.064,0.393 -3.071,0.393l-7.977,0c-0.829,0 -1.585,0.467 -1.959,1.205c-0.378,0.74 -0.305,1.625 0.187,2.296l22.62,30.884c0.412,0.566 1.07,0.901 1.771,0.901l9.915,0c0.827,0 1.587,-0.467 1.96,-1.207c0.378,-0.742 0.302,-1.629 -0.186,-2.296l-15.91,-21.688Z\"\n      style=\"fill:#000;fill-rule:nonzero;\"></path>\n    <path d=\"M107.191,80.969c-7.255,-4.794 -11.4,-8.845 -15.011,-16.109c-2.47,4.977 -8.236,12.376 -17.962,18.198c-4.856,15.106 -27.954,44.015 -35.43,39.916c-2.213,-1.212 -2.633,-2.808 -2.133,-4.456c0.536,-4.129 9.078,-13.62 9.078,-13.62c0,0 0.18,1.992 2.913,6.187c-3.609,-11.205 5.965,-25.031 8.5,-29.738c3.985,-1.269 4.274,-6.387 4.274,-6.387c0.255,-7.909 -3.278,-13.635 -6.701,-17.059c2.459,3.002 3.255,7.539 3.372,11.694l0,0.023c0.012,0.469 0.012,0.93 0.011,1.39c-0.117,3.439 -1.157,8.19 -3.383,8.19l0.006,0.03c-2.289,-0.098 -5.115,0.391 -7.639,1.18l-5.582,1.334c0,0 2.977,-0.136 4.584,1.252c-1.79,2.915 -5.769,6.533 -10.206,8.588c-6.457,2.995 -8.312,-2.964 -5.034,-6.838c0.805,-0.946 1.618,-1.745 2.387,-2.399c-0.495,-0.513 -0.807,-1.198 -0.889,-2.068c-0.001,-0.005 -0.004,-0.009 -0.005,-0.013c-0.45,-1.977 -0.202,-4.543 2.596,-8.623c0.551,-0.863 1.214,-1.748 2.007,-2.647c0.025,-0.031 0.046,-0.059 0.072,-0.089c0.034,-0.042 0.072,-0.08 0.108,-0.121c0.02,-0.023 0.039,-0.045 0.059,-0.068c0.2,-0.228 0.413,-0.45 0.639,-0.663c3.334,-3.414 8.599,-6.966 16.897,-10.152c9.675,-14.223 13.219,-16.89 13.219,-16.89c1.071,-1.096 2.943,-2.458 3.632,-2.805c-5.053,-8.781 -6.074,-21.158 -4.75,-24.493c-0.107,0.18 -0.206,0.365 -0.287,0.556c0.49,-1.143 0.819,-1.509 1.328,-2.111c1.381,-1.632 6.058,-2.488 7.737,0.971c0.895,1.844 1.063,4.232 1.034,6.023c-3.704,-0.193 -7.063,4.036 -7.063,4.036c0,0 3.067,-1.448 6.879,-1.473c0,0 1.015,0.883 2.283,2.542c-1.712,3.213 -4.524,10.021 -2.488,17.168c0.338,1.408 0.849,2.619 1.483,3.648c0.024,0.045 0.044,0.089 0.069,0.135c0.051,0.066 0.096,0.122 0.144,0.183c3.368,5.072 9.542,5.665 9.542,5.665c-2.906,-1.45 -5.274,-3.76 -6.816,-6.56c-0.8,-1.498 -1.291,-2.762 -1.592,-3.761c-1.636,-6.313 0.771,-9.999 2.149,-12.471c3.17,-4.917 8.944,-7.893 15.151,-7.185c8.712,0.995 14.968,8.862 13.973,17.571c-0.608,5.321 -3.781,9.723 -8.142,12.117c1.049,2.839 -0.073,6.28 -0.073,6.28c2.642,3.323 2.758,5.238 2.667,7.017c-3.357,-0.565 -6.618,1.701 -6.618,1.701c0,0 6.476,-1.546 10.238,1.81c2.446,2.631 4.078,5.009 5.051,6.766c1.393,2.505 7.859,2.683 7.123,7.188c-0.737,4.499 -5.669,4.542 -13.401,-0.56M69.571,0c-38.424,0 -69.571,31.148 -69.571,69.567c0,38.422 31.147,69.573 69.571,69.573c38.42,0 69.568,-31.151 69.568,-69.573c0,-38.42 -31.148,-69.567 -69.568,-69.567\"\n      style=\"fill:#000;fill-rule:nonzero;\"></path>\n    <path d=\"M73.796,51.693c0.813,-0.814 0.813,-2.134 0,-2.947c-0.815,-0.814 -2.133,-0.814 -2.947,0c-0.815,0.813 -0.815,2.133 0,2.947c0.814,0.813 2.132,0.813 2.947,0\" style=\"fill:#000;fill-rule:nonzero;\"></path>\n    <path d=\"M66.445,53.149c-0.814,0.813 -0.814,2.133 0,2.947c0.813,0.814 2.133,0.814 2.947,0c0.813,-0.814 0.813,-2.134 0,-2.947c-0.814,-0.813 -2.134,-0.813 -2.947,0\" style=\"fill:#000;fill-rule:nonzero;\"></path>\n    <path d=\"M79.231,54.233c-1.274,-1.274 -3.339,-1.272 -4.611,0l-2.713,2.712c-1.274,1.275 -1.274,3.339 0,4.612l2.978,2.978c1.274,1.275 3.338,1.274 4.611,0l2.712,-2.712c1.274,-1.274 1.274,-3.339 0,-4.612l-2.977,-2.978Z\" style=\"fill:#000;fill-rule:nonzero;\"></path>\n    <path d=\"M95.759,41.445c-2.151,-2.578 1.869,-7.257 4.391,-4.463c4.645,5.148 -2.237,7.041 -4.391,4.463M105.004,44.132c3.442,-6.553 -1.427,-10.381 -4.773,-13.523c-5.36,-5.039 -10.706,-7.217 -16.811,-0.241c-6.102,6.977 -2.226,15.068 3.356,19.061c5.584,3.994 14.782,1.255 18.228,-5.297\"\n      style=\"fill:#000;fill-rule:nonzero;\"></path>\n  </svg>\n</a>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/menu-footer.html",
    "content": "<p>Built with <a href=\"https://github.com/matcornic/hugo-theme-learn\"><i class=\"fa fa-heart\"></i></a> from <a href=\"http://getgrav.org\">Grav</a> and <a href=\"http://gohugo.io/\">Hugo</a></p>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/menu.html",
    "content": "<nav id=\"sidebar\" class=\"{{if $.Site.Params.showVisitedLinks }}showVisitedLinks{{end}}\">\n\n{{ $currentNode := . }}\n{{ $showvisitedlinks := .Site.Params.showVisitedLinks }}\n  <div id=\"header-wrapper\">\n    <!-- <div id=\"header\">\n      {{ partial \"logo.html\" . }}\n    </div> -->\n    {{if not .Site.Params.disableSearch}}\n        {{ partial \"search.html\" . }}\n    {{end}}\n  </div>\n\n    <div class=\"highlightable\">\n    <div class=\"leftMenu\">\n    <ul class=\"topics\">\n\n        {{if eq .Site.Params.ordersectionsby \"title\"}}  \n          {{range .Site.Home.Sections.ByTitle}}\n          {{ template \"section-tree-nav\" dict \"sect\" . \"currentnode\" $currentNode \"showvisitedlinks\" $showvisitedlinks}}\n          {{end}}\n        {{else}}\n          {{range .Site.Home.Sections.ByWeight}}\n          {{ template \"section-tree-nav\" dict \"sect\" . \"currentnode\" $currentNode \"showvisitedlinks\" $showvisitedlinks}}\n          {{end}}\n        {{end}} \n    </ul>\n\n    {{ $disableShortcutsTitle := .Site.Params.DisableShortcutsTitle}}\n    {{with .Site.Menus.shortcuts}}\n      <section id=\"shortcuts\">\n        <h3>{{ if not $disableShortcutsTitle}}{{ T \"Shortcuts-Title\"}}{{ end }}</h3>\n        <ul>\n          {{ range sort . \"Weight\"}}\n              <li> \n                  {{.Pre}}<a class=\"padding\" href=\"{{.URL | absLangURL }}\">{{safeHTML .Name}}</a>{{.Post}}\n              </li>\n          {{end}}\n        </ul>\n      </section>\n    {{end}}\n  </div>\n    <!-- {{ if or .Site.IsMultiLingual $showvisitedlinks }}\n    <section id=\"prefooter\">\n      <hr/>\n      <ul>\n      {{ if and .Site.IsMultiLingual (not .Site.Params.DisableLanguageSwitchingButton)}}\n        <li>\n          <a class=\"padding\">\n            <i class=\"fa fa-fw fa-language\"></i>\n          <div class=\"select-style\">\n            <select id=\"select-language\" onchange=\"location = this.value;\">\n          {{ $siteLanguages := .Site.Languages}}\n          {{ $pageLang := .Page.Lang}}\n          {{ range .Page.AllTranslations }}\n              {{ $translation := .}}\n              {{ range $siteLanguages }}\n                  {{ if eq $translation.Lang .Lang }}\n                    {{ $selected := false }}\n                    {{ if eq $pageLang .Lang}}\n                      <option id=\"{{ $translation.Language }}\" value=\"{{ $translation.URL }}\" selected>{{ .LanguageName }}</option>\n                    {{ else }}\n                      <option id=\"{{ $translation.Language }}\" value=\"{{ $translation.URL }}\">{{ .LanguageName }}</option>\n                    {{ end }}\n                  {{ end }}\n              {{ end }}\n          {{ end }}\n        </select>\n        <svg version=\"1.1\" id=\"Capa_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n          width=\"255px\" height=\"255px\" viewBox=\"0 0 255 255\" style=\"enable-background:new 0 0 255 255;\" xml:space=\"preserve\">\n          <g>\n            <g id=\"arrow-drop-down\">\n              <polygon points=\"0,63.75 127.5,191.25 255,63.75 \t\t\" />\n            </g>\n          </g>\n        </svg>\n        </div>\n        </a>\n        </li>\n      {{end}} \n      \n      {{ if $showvisitedlinks}}\n        <li><a class=\"padding\" href=\"#\" data-clear-history-toggle=\"\"><i class=\"fa fa-fw fa-history\"></i> {{T \"Clear-History\"}}</a></li>         \n      {{ end }}\n      </ul>\n    </section>\n    {{ end }} -->\n\n    <!-- download button -->\n    <!-- <hr /> -->\n    {{ if eq .Lang \"en\"}}\n      <a class=\"padding\" href=\"{{\"https://shardingsphere.apache.org/pdf/shardingsphere-elasticjob_docs_en.pdf\" | absURL}}\">\n        <i class=\"fa fa-fw fa-file-pdf-o\" ></i>&nbsp;Download PDF&nbsp;&nbsp;<!-- &nbsp; is a placeholder -->\n    {{ else }}  \n      <a class=\"padding\" href=\"{{\"https://shardingsphere.apache.org/pdf/shardingsphere-elasticjob_docs_cn.pdf\" | absURL}}\">\n        <i class=\"fa fa-fw fa-file-pdf-o\" ></i>&nbsp;下载PDF文档&nbsp;&nbsp;<!-- &nbsp; is a placeholder -->\n    {{end}}\n    </a>\n\n    <section id=\"footer\">\n      {{ partial \"menu-footer.html\" . }}\n    </section>\n  </div>\n</nav>\n\n<!-- templates -->\n{{ define \"section-tree-nav\" }}\n{{ $showvisitedlinks := .showvisitedlinks }}\n{{ $currentNode := .currentnode }}\n {{with .sect}}\n  {{if .IsSection}}\n    {{safeHTML .Params.head}}\n    <li data-nav-id=\"{{.URL}}\" title=\"{{.Title}}\" class=\"dd-item \n        {{if .IsAncestor $currentNode }}parent{{end}}\n        {{if eq .UniqueID $currentNode.UniqueID}}active{{end}}\n        {{if .Params.alwaysopen}}parent{{end}}\n        \">\n      {{ $numberOfPages := (add (len .Pages) (len .Sections)) }}      \n      <a href=\"{{.RelPermalink}}\">\n         <i class=\"collapse\" style=\"display:inline; font-family:'courier';\">\n         {{ if ne $numberOfPages 0 }}\n             <svg  class=\"icon icon-down\" \n              style=\"display: {{if .IsAncestor $currentNode }}inline-block;{{else}}none;{{end}}\"\n              viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"   width=\"20\" height=\"20\" fill=\"#777\">\n              <path d=\"M500.8 604.778667L267.306667 371.392l-45.226667 45.269333 278.741333 278.613334 278.485334-278.613334-45.248-45.248z\" p-id=\"5376\" ></path>\n            </svg>\n            <svg  class=\"icon icon-right\" \n              style=\"display: {{if .IsAncestor $currentNode }}none;{{else}}inline-block;{{end}}\"\n              viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"  width=\"20\" height=\"20\" fill=\"#777\">\n              <path d=\"M593.450667 512.128L360.064 278.613333l45.290667-45.226666 278.613333 278.762666L405.333333 790.613333l-45.226666-45.269333z\" p-id=\"5605\" ></path>\n            </svg>\n          {{else}}\n            <svg  viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"5375\" width=\"20\" height=\"20\"></svg>\n          {{end}}\n          </i>\n          {{safeHTML .Params.Pre}}{{or .Params.menuTitle .LinkTitle .Title}}{{safeHTML .Params.Post}}\n          {{ if $showvisitedlinks}}\n            <i class=\"fa fa-check read-icon\"></i>\n          {{ end }}\n      </a>\n      \n      {{ if ne $numberOfPages 0 }}\n        <ul>\n          {{ $currentNode.Scratch.Set \"pages\" .Pages }}\n          {{ if .Sections}}\n            {{ $currentNode.Scratch.Set \"pages\" (.Pages | union .Sections) }}\n          {{end}}\n          {{ $pages := ($currentNode.Scratch.Get \"pages\") }}\n          \n        {{if eq .Site.Params.ordersectionsby \"title\"}}  \n          {{ range $pages.ByTitle }}\n            {{ if and .Params.hidden (not $.showhidden) }} \n            {{else}}\n            {{ template \"section-tree-nav\" dict \"sect\" . \"currentnode\" $currentNode \"showvisitedlinks\" $showvisitedlinks }}\n            {{end}}\n          {{ end }}\n        {{else}}\n          {{ range $pages.ByWeight }}\n            {{ if and .Params.hidden (not $.showhidden) }} \n            {{else}}\n            {{ template \"section-tree-nav\" dict \"sect\" . \"currentnode\" $currentNode \"showvisitedlinks\" $showvisitedlinks }}\n            {{end}}\n          {{ end }}\n        {{end}}\n        </ul>\n      {{ end }}        \n    </li>\n  {{else}}\n    {{ if not .Params.Hidden }}\n      <li data-nav-id=\"{{.URL}}\" title=\"{{.Title}}\" class=\"dd-item {{if eq .UniqueID $currentNode.UniqueID}}active{{end}}\">\n        <a href=\"{{ .RelPermalink}}\">\n          <svg  viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"5375\" width=\"20\" height=\"20\"></svg>\n        {{safeHTML .Params.Pre}}{{or .Params.menuTitle .LinkTitle .Title}}{{safeHTML .Params.Post}}\n        {{ if $showvisitedlinks}}<i class=\"fa fa-check read-icon\"></i>{{end}}\n        </a>\n    </li>\n     {{ end }}\n  {{end}}\n {{ end }}\n{{ end }}\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/meta.html",
    "content": "<meta name=\"description\" content=\"{{ with .Description }}{{ . }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}\">\n    <meta name=\"buildDate\" content=\"{{ now.Format \"2006-01-02 15:04:05\" }}\">\n{{ with .Site.Params.author }}<meta name=\"author\" content=\"{{ . }}\">{{ end }}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/search.html",
    "content": "<div class=\"searchbox\">\n    <label for=\"search-by\"><i class=\"fa fa-search\"></i></label>\n    <input data-search-input id=\"search-by\" type=\"text\" placeholder=\"{{T \"Search-placeholder\"}}\">\n    <span data-search-clear=\"\"><i class=\"fa fa-close\"></i></span>\n</div>\n{{ $assetBusting := not .Site.Params.disableAssetsBusting }}\n<script type=\"text/javascript\" src=\"{{\"js/lunr.min.js\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\"></script>\n<script type=\"text/javascript\" src=\"{{\"js/auto-complete.js\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\"></script>\n<script type=\"text/javascript\">\n    {{ if .Site.IsMultiLingual }}\n        var baseurl = \"{{.Site.LanguagePrefix | relURL }}\";\n    {{ else }}\n        var baseurl = '{{ \"\" | relURL }}';\n    {{ end }}\n</script>\n<script type=\"text/javascript\" src=\"{{\"js/search.js\" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}\"></script>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/partials/toc.html",
    "content": "<div class=\"progress\">\n    <div class=\"wrapper\">\n{{ .TableOfContents }}\n    </div>\n</div>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/shortcodes/attachments.html",
    "content": "<section class=\"attachments {{ with .Get \"style\"}}{{.}}{{ end }}\">\n\t<label>\n\t\t<i class=\"fa fa-paperclip\" aria-hidden=\"true\"></i>\n\t\t{{with .Get \"title\"}}{{.}}{{else}}{{T \"Attachments-label\"}}{{end}}\n\t</label>\n\t{{if eq .Page.File.BaseFileName \"index\"}}\n\t\t{{$.Scratch.Add \"filesName\" \"files\"}}\n\t{{else}}\n\t\t{{$.Scratch.Add \"filesName\" (printf \"%s.files\" .Page.File.BaseFileName)}}\n\t{{end}}\n\t<div class=\"attachments-files\">\n\t{{ range (readDir (printf \"./content/%s%s\" .Page.File.Dir ($.Scratch.Get \"filesName\")) ) }}\n\t\t{{ $fileDir := replace $.Page.File.Dir \"\\\\\" \"/\" }}\n\t\t{{if ($.Get \"pattern\")}}\n\t\t\t{{if (findRE ($.Get \"pattern\") .Name)}}\n\t\t\t\t<li>\n\t\t\t\t\t<a href=\"{{ (printf \"%s%s/%s\" $fileDir ($.Scratch.Get \"filesName\") .Name) | relURL }}\" >\n\t\t\t\t\t\t{{.Name}}\n\t\t\t\t\t</a>\n\t\t\t\t\t({{div .Size 1024 }} ko)\n\t\t\t\t</li>\n\t\t\t{{end}}\n\t\t{{else}}\n\t\t\t<li>\n\t\t\t\t<a href=\"{{ (printf \"%s%s/%s\" $fileDir ($.Scratch.Get \"filesName\") .Name) | relURL }}\" >\n\t\t\t\t\t{{.Name}}\n\t\t\t\t</a>\n\t\t\t\t({{div .Size 1024 }} ko)\n\t\t\t</li>\n\t\t{{end}}\n\t{{end}}\n\t<div>\n\t{{.Inner}}\n</section>\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/shortcodes/button.html",
    "content": "<a {{ with .Get \"href\"}} href=\"{{.}}\" target=\"_blank\" {{ end }} class=\"btn btn-default\">\n  {{ $icon := .Get \"icon\" }}\n  {{ $iconposition := .Get \"icon-position\" }}\n  {{ if ($icon) }}\n    {{ if or (not ($iconposition)) (eq $iconposition \"left\") }}\n  <i class=\"{{$icon}}\"></i>\n    {{ end }}\n  {{ end }}\n  {{ .Inner }}\n  {{ if and ($icon) (eq $iconposition \"right\")}}\n  <i class=\"{{$icon}}\"></i>\n  {{ end }}\n</a>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/shortcodes/children.html",
    "content": "{{ $showhidden := .Get \"showhidden\"}}\n{{ $style :=  .Get \"style\" | default \"li\" }}\n{{ $depth :=  .Get \"depth\" | default 1 }}\n{{ $withDescription :=  .Get \"description\" | default false }}\n{{ $sortTerm :=  .Get \"sort\" | default \"Weight\" }}\n\n\n<ul class=\"children children-{{$style}}\">\n\t{{ .Scratch.Set \"pages\" .Page.Pages }}\n    {{ if .Page.Sections}}\n\t    {{ .Scratch.Set \"pages\" (.Page.Pages | union .Page.Sections) }}\n    {{end}}\n    {{ $pages := (.Scratch.Get \"pages\") }}\n\n\t{{if eq $sortTerm \"Weight\"}}\n\t\t{{template \"childs\" dict \"menu\" $pages.ByWeight \"style\" $style \"showhidden\" $showhidden \"count\" 1 \"depth\" $depth \"pages\" .Site.Pages \"description\" $withDescription \"sortTerm\" $sortTerm}}\n\t{{else if eq $sortTerm \"Name\"}}\n\t\t{{template \"childs\" dict \"menu\" $pages.ByTitle \"style\" $style \"showhidden\" $showhidden \"count\" 1 \"depth\" $depth \"pages\" .Site.Pages \"description\" $withDescription \"sortTerm\" $sortTerm}}\n\t{{else if eq $sortTerm \"PublishDate\"}}\n\t\t{{template \"childs\" dict \"menu\" $pages.ByPublishDate \"style\" $style \"showhidden\" $showhidden \"count\" 1 \"depth\" $depth \"pages\" .Site.Pages \"description\" $withDescription \"sortTerm\" $sortTerm}}\n\t{{else if eq $sortTerm \"Date\"}}\n\t\t{{template \"childs\" dict \"menu\" $pages.ByDate \"style\" $style \"showhidden\" $showhidden \"count\" 1 \"depth\" $depth \"pages\" .Site.Pages \"description\" $withDescription \"sortTerm\" $sortTerm}}\n\t{{else if eq $sortTerm \"Length\"}}\n\t\t{{template \"childs\" dict \"menu\" $pages.ByLength \"style\" $style \"showhidden\" $showhidden \"count\" 1 \"depth\" $depth \"pages\" .Site.Pages \"description\" $withDescription \"sortTerm\" $sortTerm}}\n\t{{else}}\n\t\t{{template \"childs\" dict \"menu\" $pages \"style\" $style \"showhidden\" $showhidden \"count\" 1 \"depth\" $depth \"pages\" .Site.Pages \"description\" $withDescription \"sortTerm\" $sortTerm}}\n\t{{end}}\n</ul>\n\n{{.Inner|safeHTML}}\n\n{{ define \"childs\" }}\n\t{{ range .menu }}\n\t\t{{ if and .Params.hidden (not $.showhidden) }} \n\t\t{{else}}\n  \n\n{{if hasPrefix $.style \"h\"}}\n\t{{$num := sub ( int (trim $.style \"h\") ) 1 }}\n\t{{$numn := add $num $.count }}\n\n{{(printf \"<h%d>\" $numn)|safeHTML}}\n<a href=\"{{.URL}}\" >{{ .Title }}</a>\n{{(printf \"</h%d>\" $numn)|safeHTML}}\n\n{{else}}\n{{(printf \"<%s>\" $.style)|safeHTML}}\n<a href=\"{{.URL}}\" >{{ .Title }}</a>\n{{(printf \"</%s>\" $.style)|safeHTML}}\n{{end}}\n\n\n\n\n\n\t\t\t{{if $.description}}\n\t\t\t\t{{if .Description}}\n<p>{{.Description}}</p>\n\t\t\t\t{{else}}\n<p>{{.Summary}}</p>\n\t\t\t\t{{end}}\n\t\t\t{{end}}\n\t\t\n\n\t\t\n\t\t\t{{ if lt $.count $.depth}}\n{{if eq $.style \"li\"}}\n<ul>\n{{end}}\n\t{{ $.Page.Scratch.Set \"pages\" .Pages }}\n    {{ if .Sections}}\n\t    {{ $.Page.Scratch.Set \"pages\" (.Pages | union .Sections) }}\n    {{end}}\n    {{ $pages := ($.Page.Scratch.Get \"pages\") }}\n\n\t{{if eq $.sortTerm \"Weight\"}}\n\t\t{{template \"childs\" dict \"menu\" $pages.ByWeight  \"style\" $.style \"showhidden\" $.showhidden \"count\" (add $.count 1) \"depth\" $.depth \"pages\" $.pages \"description\" $.description \"sortTerm\" $.sortTerm}}\n\t{{else if eq $.sortTerm \"Name\"}}\n\t\t{{template \"childs\" dict \"menu\" $pages.ByTitle  \"style\" $.style \"showhidden\" $.showhidden \"count\" (add $.count 1) \"depth\" $.depth \"pages\" $.pages \"description\" $.description \"sortTerm\" $.sortTerm}}\n\t{{else if eq $.sortTerm \"PublishDate\"}}\n\t\t{{template \"childs\" dict \"menu\" $pages.ByPublishDate  \"style\" $.style \"showhidden\" $.showhidden \"count\" (add $.count 1) \"depth\" $.depth \"pages\" $.pages \"description\" $.description \"sortTerm\" $.sortTerm}}\n\t{{else if eq $.sortTerm \"Date\"}}\n\t\t{{template \"childs\" dict \"menu\" $pages.ByDate  \"style\" $.style \"showhidden\" $.showhidden \"count\" (add $.count 1) \"depth\" $.depth \"pages\" $.pages \"description\" $.description \"sortTerm\" $.sortTerm}}\n\t{{else if eq $.sortTerm \"Length\"}}\n\t\t{{template \"childs\" dict \"menu\" $pages.ByLength  \"style\" $.style \"showhidden\" $.showhidden \"count\" (add $.count 1) \"depth\" $.depth \"pages\" $.pages \"description\" $.description \"sortTerm\" $.sortTerm}}\n\t{{else}}\n\t\t{{template \"childs\" dict \"menu\" $pages  \"style\" $.style \"showhidden\" $.showhidden \"count\" (add $.count 1) \"depth\" $.depth \"pages\" $.pages \"description\" $.description \"sortTerm\" $.sortTerm}}\n\t{{end}}\n{{if eq $.style \"li\"}}\n</ul>\n{{end}}\n\t\t\t{{end}}\n\n\t\t{{end}}\n\t{{end}}\n{{end}}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/shortcodes/expand.html",
    "content": "<div class=\"expand\">\n    <div class=\"expand-label\" style=\"cursor: pointer;\" onclick=\"$h = $(this);$h.next('div').slideToggle(100,function () {$h.children('i').attr('class',function () {return $h.next('div').is(':visible') ? 'fa fa-chevron-down' : 'fa fa-chevron-right';});});\">\n        <i style=\"font-size:x-small;\" class=\"fa fa-chevron-right\"></i>\n        <span>\n        {{$expandMessage := T \"Expand-title\"}}\n    \t{{ if .IsNamedParams }}\n    \t{{.Get \"default\" | default $expandMessage}}\n    \t{{else}}\n    \t{{.Get 0 | default $expandMessage}}\n    \t{{end}}\n    \t</span>\n    </div>\n    <div class=\"expand-content\" style=\"display: none;\">\n        {{.Inner | safeHTML}}\n    </div>\n</div>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/shortcodes/mermaid.html",
    "content": "<div class=\"mermaid\" align=\"{{ if .Get \"align\" }}{{ .Get \"align\" }}{{ else }}center{{ end }}\">{{ safeHTML .Inner }}</div>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/shortcodes/notice.html",
    "content": "<div class=\"notices {{ .Get 0 }}\" {{ if len .Params | eq 2 }} id=\"{{ .Get 1 }}\" {{ end }}>{{ .Inner }}</div>\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/shortcodes/ref.html",
    "content": "{{- if in (.Get 0) \"/_index.md\" -}}\n\t{{- $paths := (split (.Get 0) \"_index.md\") -}}\n\t{{- $pagepath := index $paths 0 -}}\n\t{{- $anchor := index $paths 1 -}}\n\t{{- with .Site.GetPage \"section\" (trim $pagepath \"/\") -}}\n\t\t{{- ( printf \"%s%s\" $pagepath $anchor ) | relLangURL -}}\n\t{{- end -}}\n{{- else -}}\n\t{{- with .Site.GetPage \"section\" (.Get 0) }}\n\t\t{{- .URL -}}\n\t{{- else -}}\n\t\t{{- .Get 0 | relref .Page -}}\n\t{{- end -}}\n{{- end -}}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/shortcodes/relref.html",
    "content": "{{- if in (.Get 0) \"/_index.md\" -}}\n\t{{- $paths := (split (.Get 0) \"_index.md\") -}}\n\t{{- $pagepath := index $paths 0 -}}\n\t{{- $anchor := index $paths 1 -}}\n\t{{- with .Site.GetPage \"section\" (trim $pagepath \"/\") -}}\n\t\t{{- ( printf \"%s%s\" $pagepath $anchor ) | relLangURL -}}\n\t{{- end -}}\n{{- else -}}\n\t{{- with .Site.GetPage \"section\" (.Get 0) }}\n\t\t{{- .URL -}}\n\t{{- else -}}\n\t\t{{- .Get 0 | relref .Page -}}\n\t{{- end -}}\n{{- end -}}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/layouts/shortcodes/siteparam.html",
    "content": "{{- $paramName := (.Get 0) -}}\n{{- $siteParams := .Site.Params -}}\n{{- with $paramName -}}\n    {{- with $siteParams -}}\n        {{- index . (lower $paramName) -}}\n    {{- end -}}\n{{- end -}}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/css/auto-complete.css",
    "content": ".autocomplete-suggestions {\n    text-align: left;\n    cursor: default;\n    border: 1px solid #ccc;\n    border-top: 0;\n    background: #fff;\n    box-shadow: -1px 1px 3px rgba(0,0,0,.1);\n\n    /* core styles should not be changed */\n    position: absolute;\n    display: none;\n    z-index: 9999;\n    max-height: 254px;\n    overflow: hidden;\n    overflow-y: auto;\n    box-sizing: border-box;\n    \n}\n.autocomplete-suggestion {\n    position: relative;\n    cursor: pointer;\n    padding: 7px;\n    line-height: 23px;\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    color: #333;\n}\n\n.autocomplete-suggestion b {\n    font-weight: normal;\n    color: #1f8dd6;\n}\n\n.autocomplete-suggestion.selected {\n    background: #333;\n    color: #fff;\n}\n\n.autocomplete-suggestion:hover {\n    background: #444;\n    color: #fff;\n}\n\n.autocomplete-suggestion > .context {\n    font-size: 12px;\n}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/css/hugo-theme.css",
    "content": "/* Insert here special css for hugo theme, on top of any other imported css */\n\n\n/* Table of contents */\n\n.progress ul {\n  list-style: none;\n  margin: 0;\n  padding: 0 5px;\n}\n\n#TableOfContents {\n    font-size: 1.1rem !important;\n    /* max-height: 85vh; */\n    overflow: visible;\n    padding: 5px !important;\n}\n\n#TableOfContents > ul > li > ul > li > ul li {\n  margin-right: 8px;\n}\n\n#TableOfContents > ul > li > a   {\n  /* font-weight: bold;  */\n  padding: 0 18px; margin: 0 2px;\n}\n\n#TableOfContents > ul > li > ul > li > a {\n  /* font-weight: bold; */\n}\n\n#TableOfContents > ul > li > ul > li > ul > li > ul > li > ul > li  {\n    display: none;\n}\n\nbody {\n    font-size: 16px !important;\n    color: #323232 !important;\n}\n\n#body a.highlight, #body a.highlight:hover, #body a.highlight:focus {\n    text-decoration: none;\n    outline: none;\n    outline: 0;\n}\n#body a.highlight {\n    line-height: 1.1;\n    display: inline-block;\n}\n#body a.highlight:after {\n    display: block;\n    content: \"\";\n    height: 1px;\n    width: 0%;\n    background-color: #0082a7; /*#CE3B2F*/\n    -webkit-transition: width 0.5s ease;\n    -moz-transition: width 0.5s ease;\n    -ms-transition: width 0.5s ease;\n    transition: width 0.5s ease;\n}\n#body a.highlight:hover:after, #body a.highlight:focus:after {\n    width: 100%;\n}\n.progress {\n    position:absolute;\n    background-color: rgba(246, 246, 246, 0.97);\n    width: auto;\n    border: thin solid #ECECEC;\n    display:none;\n    z-index:200;\n}\n\n#toc-menu {\n  border-right: thin solid #DAD8D8 !important;\n  padding-right: 1rem !important;\n  margin-right: 0.5rem !important;\n}\n\n#sidebar-toggle-span {\n  border-right: thin solid #DAD8D8 !important;\n  padding-right: 0.5rem !important;\n  margin-right: 1rem !important;\n}\n\n.btn {\n  display: inline-block !important;\n  padding: 6px 12px !important;\n  margin-bottom: 0 !important;\n  font-size: 14px !important;\n  font-weight: normal !important;\n  line-height: 1.42857143 !important;\n  text-align: center !important;\n  white-space: nowrap !important;\n  vertical-align: middle !important;\n  -ms-touch-action: manipulation !important;\n      touch-action: manipulation !important;\n  cursor: pointer !important;\n  -webkit-user-select: none !important;\n     -moz-user-select: none !important;\n      -ms-user-select: none !important;\n          user-select: none !important;\n  background-image: none !important;\n  border: 1px solid transparent !important;\n  border-radius: 4px !important;\n  -webkit-transition: all 0.15s !important;\n     -moz-transition: all 0.15s !important;\n          transition: all 0.15s !important;\n}\n.btn:focus {\n  /*outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;*/\n  outline: none !important;\n}\n.btn:hover,\n.btn:focus {\n  color: #2b2b2b !important;\n  text-decoration: none !important;\n}\n\n.btn-default {\n  color: #333 !important;\n  background-color: #fff !important;\n  border-color: #ccc !important;\n}\n.btn-default:hover,\n.btn-default:focus,\n.btn-default:active {\n  color: #fff !important;\n  background-color: #9e9e9e !important;\n  border-color: #9e9e9e !important;\n}\n.btn-default:active {\n  background-image: none !important;\n}\n\n/* anchors */\n.anchor {\n  color: #00bdf3;\n  font-size: 0.5em;\n  cursor:pointer;\n  visibility:hidden;\n  margin-left: 0.5em;\n    position: absolute;\n    margin-top:0.1em;\n}\n\nh2:hover .anchor, h3:hover .anchor, h4:hover .anchor, h5:hover .anchor, h6:hover .anchor {\n  visibility:visible;\n}\n\n/* Redfines headers style */\n\nh2, h3, h4, h5, h6 {\n  font-weight: 400;\n  line-height: 1.1;\n}\n\nh1 a, h2 a, h3 a, h4 a, h5 a, h6 a {\n  font-weight: inherit;\n}\n\nh1 {\n  font-size: 2.0rem;\n  line-height: 110% !important;\n  margin: 2.0rem 0 1.0rem 0;\n}\n\nh2 {\n  /* font-size: 1.75rem; */\n  font-size: 1.5rem;\n  line-height: 110% !important;\n  /* margin: 1.5rem 0 1.0rem 0; */\n  margin: 4.5rem 0 2rem 0;\n}\n\nh3 {\n  font-size: 1.5rem;\n  line-height: 110% !important;\n  margin: 1.2rem 0 0.8rem 0;\n}\n\nh4 {\n  font-size: 1.25rem;\n  line-height: 110% !important;\n  margin: 1.1rem 0 0.6rem 0;\n}\n\nh5 {\n  font-size: 1rem;\n  line-height: 110% !important;\n  margin: 1rem 0 0.2rem 0;\n}\n\nh6 {\n  font-size: 0.5rem;\n  line-height: 110% !important;\n  margin: 0.5rem 0 0.2rem 0;\n}\n\np {\n    margin: 1rem 0;\n}\n\nfigcaption h4 {\n    font-weight: 300 !important;\n    opacity: .85;\n    font-size: 1em;\n    text-align: center;\n    margin-top: -1.5em;\n}\n\n.select-style {\n    border: 0;\n    width: 150px;\n    border-radius: 0px;\n    overflow: hidden;\n    display: inline-flex;\n}\n\n.select-style svg {\n    fill: #ccc;\n    width: 14px;\n    height: 14px;\n    pointer-events: none;\n    margin: auto;\n}\n\n.select-style svg:hover {\n  fill: #e6e6e6;\n}\n\n.select-style select {\n    padding: 0;\n    width: 130%;\n    border: none;\n    box-shadow: none;\n    background: transparent;\n    background-image: none;\n    -webkit-appearance: none;\n    margin: auto;\n    margin-left: 0px;\n    margin-right: -20px;\n}\n\n.select-style select:focus {\n    outline: none;\n}\n\n.select-style :hover {\n    cursor:  pointer;\n}\n\n@media only all and (max-width: 47.938em) {\n  #breadcrumbs .links, #top-github-link-text {\n      display: none;\n  }\n}\n\n.is-sticky #top-bar {\n  box-shadow: -1px 2px 5px 1px rgba(0, 0, 0, 0.1); \n}"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/css/hybrid.css",
    "content": "/*\n\nvim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid)\n\n*/\n\n/*background color*/\n.hljs {\n  display: block;\n  overflow-x: auto;\n  padding: 0.5em;\n  /* background: #1d1f21; */\n}\n\n/*selection color*/\n.hljs::selection,\n.hljs span::selection {\n  background: #373b41;\n}\n\n.hljs::-moz-selection,\n.hljs span::-moz-selection {\n  background: #373b41;\n}\n\n/*foreground color*/\n.hljs {\n  color: #c5c8c6;\n}\n\n/*color: fg_yellow*/\n.hljs-title,\n.hljs-name {\n  color: #f0c674;\n}\n\n/*color: fg_comment*/\n.hljs-comment,\n.hljs-meta,\n.hljs-meta .hljs-keyword {\n  color: #707880;\n}\n\n/*color: fg_red*/\n.hljs-number,\n.hljs-symbol,\n.hljs-literal,\n.hljs-deletion,\n.hljs-link {\n color: #cc6666\n}\n\n/*color: fg_green*/\n.hljs-string,\n.hljs-doctag,\n.hljs-addition,\n.hljs-regexp,\n.hljs-selector-attr,\n.hljs-selector-pseudo {\n  color: #b5bd68;\n}\n\n/*color: fg_purple*/\n.hljs-attribute,\n.hljs-code,\n.hljs-selector-id {\n color: #b294bb;\n}\n\n/*color: fg_blue*/\n.hljs-keyword,\n.hljs-selector-tag,\n.hljs-bullet,\n.hljs-tag {\n color: #81a2be;\n}\n\n/*color: fg_aqua*/\n.hljs-subst,\n.hljs-variable,\n.hljs-template-tag,\n.hljs-template-variable {\n  color: #8abeb7;\n}\n\n/*color: fg_orange*/\n.hljs-type,\n.hljs-built_in,\n.hljs-builtin-name,\n.hljs-quote,\n.hljs-section,\n.hljs-selector-class {\n  color: #de935f;\n}\n\n.hljs-emphasis {\n  font-style: italic;\n}\n\n.hljs-strong {\n  font-weight: bold;\n}\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/css/nucleus.css",
    "content": "*, *::before, *::after {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box; }\n\n@-webkit-viewport {\n  width: device-width; }\n@-moz-viewport {\n  width: device-width; }\n@-ms-viewport {\n  width: device-width; }\n@-o-viewport {\n  width: device-width; }\n@viewport {\n  width: device-width; }\nhtml {\n  font-size: 100%;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%; }\n\nbody {\n  margin: 0; }\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nnav,\nsection,\nsummary {\n  display: block; }\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline; }\n\naudio:not([controls]) {\n  display: none;\n  height: 0; }\n\n[hidden],\ntemplate {\n  display: none; }\n\na {\n  background: transparent;\n  text-decoration: none; }\n\na:active,\na:hover {\n  outline: 0; }\n\nabbr[title] {\n  border-bottom: 1px dotted; }\n\nb,\nstrong {\n  font-weight: bold; }\n\ndfn {\n  font-style: italic; }\n\nmark {\n  background: #FFFF27;\n  color: #333; }\n\nsub,\nsup {\n  font-size: 0.8rem;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline; }\n\nsup {\n  top: -0.5em; }\n\nsub {\n  bottom: -0.25em; }\n\nimg {\n  border: 0;\n  max-width: 100%;\n  padding-top: 9px; }\n\nsvg:not(:root) {\n  overflow: hidden; }\n\nfigure {\n  margin: 1em 40px; }\n\nhr {\n  height: 0; }\n\npre {\n  overflow: auto; }\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  /* color: gray; */\n  color: rgba(200, 200, 200, 1);\n  font: inherit;\n  margin: 0; }\n\nbutton {\n  overflow: visible; }\n\nbutton,\nselect {\n  text-transform: none; }\n\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer; }\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default; }\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0; }\n\ninput {\n  line-height: normal; }\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  padding: 0; }\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto; }\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; }\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none; }\n\nlegend {\n  border: 0;\n  padding: 0; }\n\ntextarea {\n  overflow: auto; }\n\noptgroup {\n  font-weight: bold; }\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n  table-layout: fixed;\n  width: 100%; }\n\ntr, td, th {\n  vertical-align: middle; }\n\nth, td {\n  padding: 0.425rem 0; }\n\nth {\n  text-align: left; }\n\n.container {\n  width: 75em;\n  margin: 0 auto;\n  padding: 0; }\n  @media only all and (min-width: 60em) and (max-width: 74.938em) {\n    .container {\n      width: 60em; } }\n  @media only all and (min-width: 48em) and (max-width: 59.938em) {\n    .container {\n      width: 48em; } }\n  @media only all and (min-width: 30.063em) and (max-width: 47.938em) {\n    .container {\n      width: 30em; } }\n  @media only all and (max-width: 30em) {\n    .container {\n      width: 100%; } }\n\n.grid {\n  display: -webkit-box;\n  display: -moz-box;\n  display: box;\n  display: -webkit-flex;\n  display: -moz-flex;\n  display: -ms-flexbox;\n  display: flex;\n  -webkit-flex-flow: row;\n  -moz-flex-flow: row;\n  flex-flow: row;\n  list-style: none;\n  margin: 0;\n  padding: 0; }\n  @media only all and (max-width: 47.938em) {\n    .grid {\n      -webkit-flex-flow: row wrap;\n      -moz-flex-flow: row wrap;\n      flex-flow: row wrap; } }\n\n.block {\n  -webkit-box-flex: 1;\n  -moz-box-flex: 1;\n  box-flex: 1;\n  -webkit-flex: 1;\n  -moz-flex: 1;\n  -ms-flex: 1;\n  flex: 1;\n  min-width: 0;\n  min-height: 0; }\n  @media only all and (max-width: 47.938em) {\n    .block {\n      -webkit-box-flex: 0;\n      -moz-box-flex: 0;\n      box-flex: 0;\n      -webkit-flex: 0 100%;\n      -moz-flex: 0 100%;\n      -ms-flex: 0 100%;\n      flex: 0 100%; } }\n\n.content {\n  margin: 0.625rem;\n  padding: 0.938rem; }\n\n@media only all and (max-width: 47.938em) {\n  body [class*=\"size-\"] {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 100%;\n    -moz-flex: 0 100%;\n    -ms-flex: 0 100%;\n    flex: 0 100%; } }\n\n.size-1-2 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 50%;\n  -moz-flex: 0 50%;\n  -ms-flex: 0 50%;\n  flex: 0 50%; }\n\n.size-1-3 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 33.33333%;\n  -moz-flex: 0 33.33333%;\n  -ms-flex: 0 33.33333%;\n  flex: 0 33.33333%; }\n\n.size-1-4 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 25%;\n  -moz-flex: 0 25%;\n  -ms-flex: 0 25%;\n  flex: 0 25%; }\n\n.size-1-5 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 20%;\n  -moz-flex: 0 20%;\n  -ms-flex: 0 20%;\n  flex: 0 20%; }\n\n.size-1-6 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 16.66667%;\n  -moz-flex: 0 16.66667%;\n  -ms-flex: 0 16.66667%;\n  flex: 0 16.66667%; }\n\n.size-1-7 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 14.28571%;\n  -moz-flex: 0 14.28571%;\n  -ms-flex: 0 14.28571%;\n  flex: 0 14.28571%; }\n\n.size-1-8 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 12.5%;\n  -moz-flex: 0 12.5%;\n  -ms-flex: 0 12.5%;\n  flex: 0 12.5%; }\n\n.size-1-9 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 11.11111%;\n  -moz-flex: 0 11.11111%;\n  -ms-flex: 0 11.11111%;\n  flex: 0 11.11111%; }\n\n.size-1-10 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 10%;\n  -moz-flex: 0 10%;\n  -ms-flex: 0 10%;\n  flex: 0 10%; }\n\n.size-1-11 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 9.09091%;\n  -moz-flex: 0 9.09091%;\n  -ms-flex: 0 9.09091%;\n  flex: 0 9.09091%; }\n\n.size-1-12 {\n  -webkit-box-flex: 0;\n  -moz-box-flex: 0;\n  box-flex: 0;\n  -webkit-flex: 0 8.33333%;\n  -moz-flex: 0 8.33333%;\n  -ms-flex: 0 8.33333%;\n  flex: 0 8.33333%; }\n\n@media only all and (min-width: 48em) and (max-width: 59.938em) {\n  .size-tablet-1-2 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 50%;\n    -moz-flex: 0 50%;\n    -ms-flex: 0 50%;\n    flex: 0 50%; }\n\n  .size-tablet-1-3 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 33.33333%;\n    -moz-flex: 0 33.33333%;\n    -ms-flex: 0 33.33333%;\n    flex: 0 33.33333%; }\n\n  .size-tablet-1-4 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 25%;\n    -moz-flex: 0 25%;\n    -ms-flex: 0 25%;\n    flex: 0 25%; }\n\n  .size-tablet-1-5 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 20%;\n    -moz-flex: 0 20%;\n    -ms-flex: 0 20%;\n    flex: 0 20%; }\n\n  .size-tablet-1-6 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 16.66667%;\n    -moz-flex: 0 16.66667%;\n    -ms-flex: 0 16.66667%;\n    flex: 0 16.66667%; }\n\n  .size-tablet-1-7 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 14.28571%;\n    -moz-flex: 0 14.28571%;\n    -ms-flex: 0 14.28571%;\n    flex: 0 14.28571%; }\n\n  .size-tablet-1-8 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 12.5%;\n    -moz-flex: 0 12.5%;\n    -ms-flex: 0 12.5%;\n    flex: 0 12.5%; }\n\n  .size-tablet-1-9 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 11.11111%;\n    -moz-flex: 0 11.11111%;\n    -ms-flex: 0 11.11111%;\n    flex: 0 11.11111%; }\n\n  .size-tablet-1-10 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 10%;\n    -moz-flex: 0 10%;\n    -ms-flex: 0 10%;\n    flex: 0 10%; }\n\n  .size-tablet-1-11 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 9.09091%;\n    -moz-flex: 0 9.09091%;\n    -ms-flex: 0 9.09091%;\n    flex: 0 9.09091%; }\n\n  .size-tablet-1-12 {\n    -webkit-box-flex: 0;\n    -moz-box-flex: 0;\n    box-flex: 0;\n    -webkit-flex: 0 8.33333%;\n    -moz-flex: 0 8.33333%;\n    -ms-flex: 0 8.33333%;\n    flex: 0 8.33333%; } }\n@media only all and (max-width: 47.938em) {\n  @supports not (flex-wrap: wrap) {\n    .grid {\n      display: block;\n      -webkit-box-lines: inherit;\n      -moz-box-lines: inherit;\n      box-lines: inherit;\n      -webkit-flex-wrap: inherit;\n      -moz-flex-wrap: inherit;\n      -ms-flex-wrap: inherit;\n      flex-wrap: inherit; }\n\n    .block {\n      display: block;\n      -webkit-box-flex: inherit;\n      -moz-box-flex: inherit;\n      box-flex: inherit;\n      -webkit-flex: inherit;\n      -moz-flex: inherit;\n      -ms-flex: inherit;\n      flex: inherit; } } }\n.first-block {\n  -webkit-box-ordinal-group: 0;\n  -webkit-order: -1;\n  -ms-flex-order: -1;\n  order: -1; }\n\n.last-block {\n  -webkit-box-ordinal-group: 2;\n  -webkit-order: 1;\n  -ms-flex-order: 1;\n  order: 1; }\n\n.fixed-blocks {\n  -webkit-flex-flow: row wrap;\n  -moz-flex-flow: row wrap;\n  flex-flow: row wrap; }\n  .fixed-blocks .block {\n    -webkit-box-flex: inherit;\n    -moz-box-flex: inherit;\n    box-flex: inherit;\n    -webkit-flex: inherit;\n    -moz-flex: inherit;\n    -ms-flex: inherit;\n    flex: inherit;\n    width: 25%; }\n    @media only all and (min-width: 60em) and (max-width: 74.938em) {\n      .fixed-blocks .block {\n        width: 33.33333%; } }\n    @media only all and (min-width: 48em) and (max-width: 59.938em) {\n      .fixed-blocks .block {\n        width: 50%; } }\n    @media only all and (max-width: 47.938em) {\n      .fixed-blocks .block {\n        width: 100%; } }\n\nbody {\n  font-size: 1.05rem;\n  line-height: 1.7; }\n\nh1, h2, h3, h4, h5, h6 {\n  margin: 0.85rem 0 1.7rem 0;\n  text-rendering: optimizeLegibility; }\n\nh1 {\n  font-size: 3.25rem; }\n\nh2 {\n  font-size: 2.55rem; }\n\nh3 {\n  font-size: 2.15rem; }\n\nh4 {\n  font-size: 1.8rem; }\n\nh5 {\n  font-size: 1.4rem; }\n\nh6 {\n  font-size: 0.9rem; }\n\np {\n  margin: 1.7rem 0; }\n\n/* ul,  */\nol {\n  margin-top: 1.7rem;\n  margin-bottom: 1.7rem; \n}\n  ul ul, ul ol, ol ul, ol ol {\n    margin-top: 0;\n    margin-bottom: 0; }\n\nblockquote {\n  margin: 1.7rem 0;\n  padding-left: 0.85rem; }\n\ncite {\n  display: block;\n  font-size: 0.925rem; }\n  cite:before {\n    content: \"\\2014 \\0020\"; }\n\npre {\n  margin: 1.7rem 0;\n  padding: 0.938rem; }\n\ncode {\n  vertical-align: bottom; }\n\nsmall {\n  font-size: 0.925rem; }\n\nhr {\n  border-left: none;\n  border-right: none;\n  border-top: none;\n  margin: 1.7rem 0; }\n\nfieldset {\n  border: 0;\n  padding: 0.938rem;\n  margin: 0 0 1.7rem 0; }\n\ninput,\nlabel,\nselect {\n  display: block; }\n\nlabel {\n  margin-bottom: 0.425rem; }\n  label.required:after {\n    content: \"*\"; }\n  label abbr {\n    display: none; }\n\ntextarea, input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"search\"], input[type=\"tel\"], input[type=\"text\"], input[type=\"url\"], input[type=\"color\"], input[type=\"date\"], input[type=\"datetime\"], input[type=\"datetime-local\"], input[type=\"month\"], input[type=\"time\"], input[type=\"week\"], select[multiple=multiple] {\n  -webkit-transition: border-color;\n  -moz-transition: border-color;\n  transition: border-color;\n  border-radius: 0.1875rem;\n  margin-bottom: 0.85rem;\n  padding: 0.425rem 0.425rem;\n  width: 100%; }\n  textarea:focus, input[type=\"email\"]:focus, input[type=\"number\"]:focus, input[type=\"password\"]:focus, input[type=\"search\"]:focus, input[type=\"tel\"]:focus, input[type=\"text\"]:focus, input[type=\"url\"]:focus, input[type=\"color\"]:focus, input[type=\"date\"]:focus, input[type=\"datetime\"]:focus, input[type=\"datetime-local\"]:focus, input[type=\"month\"]:focus, input[type=\"time\"]:focus, input[type=\"week\"]:focus, select[multiple=multiple]:focus {\n    outline: none; }\n\ntextarea {\n  resize: vertical; }\n\ninput[type=\"checkbox\"], input[type=\"radio\"] {\n  display: inline;\n  margin-right: 0.425rem; }\n\ninput[type=\"file\"] {\n  width: 100%; }\n\nselect {\n  width: auto;\n  max-width: 100%;\n  margin-bottom: 1.7rem; }\n\nbutton,\ninput[type=\"submit\"] {\n  cursor: pointer;\n  user-select: none;\n  vertical-align: middle;\n  white-space: nowrap;\n  border: inherit; }\n\n/*# sourceMappingURL=nucleus.css.map */\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/css/theme-blue.css",
    "content": "\n:root{\n    \n    --MAIN-TEXT-color:#323232; /* Color of text by default */\n    --MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */\n    --MAIN-LINK-color:#1C90F3; /* Color of links */\n    --MAIN-LINK-HOVER-color:#167ad0; /* Color of hovered links */\n    --MAIN-ANCHOR-color: #1C90F3; /* color of anchors on titles */\n\n    --MENU-HEADER-BG-color:#1C90F3; /* Background color of menu header */\n    --MENU-HEADER-BORDER-color:#33a1ff; /*Color of menu header border */ \n\n    --MENU-SEARCH-BG-color:#167ad0; /* Search field background color (by default borders + icons) */\n    --MENU-SEARCH-BOX-color: #33a1ff; /* Override search field border color */\n    --MENU-SEARCH-BOX-ICONS-color: #a1d2fd; /* Override search field icons color */\n\n    --MENU-SECTIONS-ACTIVE-BG-color:#20272b; /* Background color of the active section and its childs */\n    --MENU-SECTIONS-BG-color:#252c31; /* Background color of other sections */\n    --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */\n    --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6;  /* Color of links in menu, when hovered */\n    --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */\n    --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */\n\n    --MENU-VISITED-color: #33a1ff; /* Color of 'page visited' icons in menu */\n    --MENU-SECTION-HR-color: #20272b; /* Color of <hr> separator in menu */\n    \n}\n\nbody {\n    color: var(--MAIN-TEXT-color) !important;\n}\n\ntextarea:focus, input[type=\"email\"]:focus, input[type=\"number\"]:focus, input[type=\"password\"]:focus, input[type=\"search\"]:focus, input[type=\"tel\"]:focus, input[type=\"text\"]:focus, input[type=\"url\"]:focus, input[type=\"color\"]:focus, input[type=\"date\"]:focus, input[type=\"datetime\"]:focus, input[type=\"datetime-local\"]:focus, input[type=\"month\"]:focus, input[type=\"time\"]:focus, input[type=\"week\"]:focus, select[multiple=multiple]:focus {\n    border-color: none;\n    box-shadow: none;\n}\n\nh2, h3, h4, h5 {\n    color: var(--MAIN-TITLES-TEXT-color) !important;\n}\n\na {\n    color: var(--MAIN-LINK-color);\n}\n\n.anchor {\n    color: var(--MAIN-ANCHOR-color);\n}\n\na:hover {\n    color: var(--MAIN-LINK-HOVER-color);\n}\n\n#sidebar ul li.visited > a .read-icon {\n\tcolor: var(--MENU-VISITED-color);\n}\n\n#body a.highlight:after {\n    display: block;\n    content: \"\";\n    height: 1px;\n    width: 0%;\n    -webkit-transition: width 0.5s ease;\n    -moz-transition: width 0.5s ease;\n    -ms-transition: width 0.5s ease;\n    transition: width 0.5s ease;\n    background-color: var(--MAIN-LINK-HOVER-color);\n}\n#sidebar {\n\tbackground-color: var(--MENU-SECTIONS-BG-color);\n}\n#sidebar #header-wrapper {\n    background: var(--MENU-HEADER-BG-color);\n    color: var(--MENU-SEARCH-BOX-color);\n    border-color: var(--MENU-HEADER-BORDER-color);\n}\n#sidebar .searchbox {\n\tborder-color: var(--MENU-SEARCH-BOX-color);\n    background: var(--MENU-SEARCH-BG-color);\n}\n#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {\n    background: var(--MENU-SECTIONS-ACTIVE-BG-color);\n}\n#sidebar .searchbox * {\n    color: var(--MENU-SEARCH-BOX-ICONS-color);\n}\n\n#sidebar a {\n    color: var(--MENU-SECTIONS-LINK-color);\n}\n\n#sidebar a:hover {\n    color: var(--MENU-SECTIONS-LINK-HOVER-color);\n}\n\n#sidebar ul li.active > a {\n    background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);\n    color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;\n}\n\n#sidebar hr {\n    border-color: var(--MENU-SECTION-HR-color);\n}\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/css/theme-green.css",
    "content": "\n:root{\n    \n    --MAIN-TEXT-color:#323232; /* Color of text by default */\n    --MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */\n    --MAIN-LINK-color:#599a3e; /* Color of links */\n    --MAIN-LINK-HOVER-color:#3f6d2c; /* Color of hovered links */\n    --MAIN-ANCHOR-color: #599a3e; /* color of anchors on titles */\n\n    --MENU-HEADER-BG-color:#74b559; /* Background color of menu header */\n    --MENU-HEADER-BORDER-color:#9cd484; /*Color of menu header border */ \n    \n    --MENU-SEARCH-BG-color:#599a3e; /* Search field background color (by default borders + icons) */\n    --MENU-SEARCH-BOX-color: #84c767; /* Override search field border color */\n    --MENU-SEARCH-BOX-ICONS-color: #c7f7c4; /* Override search field icons color */\n\n    --MENU-SECTIONS-ACTIVE-BG-color:#1b211c; /* Background color of the active section and its childs */\n    --MENU-SECTIONS-BG-color:#222723; /* Background color of other sections */\n    --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */\n    --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6;  /* Color of links in menu, when hovered */\n    --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */\n    --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */\n\n    --MENU-VISITED-color: #599a3e; /* Color of 'page visited' icons in menu */\n    --MENU-SECTION-HR-color: #18211c; /* Color of <hr> separator in menu */\n    \n}\n\nbody {\n    color: var(--MAIN-TEXT-color) !important;\n}\n\ntextarea:focus, input[type=\"email\"]:focus, input[type=\"number\"]:focus, input[type=\"password\"]:focus, input[type=\"search\"]:focus, input[type=\"tel\"]:focus, input[type=\"text\"]:focus, input[type=\"url\"]:focus, input[type=\"color\"]:focus, input[type=\"date\"]:focus, input[type=\"datetime\"]:focus, input[type=\"datetime-local\"]:focus, input[type=\"month\"]:focus, input[type=\"time\"]:focus, input[type=\"week\"]:focus, select[multiple=multiple]:focus {\n    border-color: none;\n    box-shadow: none;\n}\n\nh2, h3, h4, h5 {\n    color: var(--MAIN-TITLES-TEXT-color) !important;\n}\n\na {\n    color: var(--MAIN-LINK-color);\n}\n\n.anchor {\n    color: var(--MAIN-ANCHOR-color);\n}\n\na:hover {\n    color: var(--MAIN-LINK-HOVER-color);\n}\n\n#sidebar ul li.visited > a .read-icon {\n\tcolor: var(--MENU-VISITED-color);\n}\n\n#body a.highlight:after {\n    display: block;\n    content: \"\";\n    height: 1px;\n    width: 0%;\n    -webkit-transition: width 0.5s ease;\n    -moz-transition: width 0.5s ease;\n    -ms-transition: width 0.5s ease;\n    transition: width 0.5s ease;\n    background-color: var(--MAIN-LINK-HOVER-color);\n}\n#sidebar {\n\tbackground-color: var(--MENU-SECTIONS-BG-color);\n}\n#sidebar #header-wrapper {\n    background: var(--MENU-HEADER-BG-color);\n    color: var(--MENU-SEARCH-BOX-color);\n    border-color: var(--MENU-HEADER-BORDER-color);\n}\n#sidebar .searchbox {\n\tborder-color: var(--MENU-SEARCH-BOX-color);\n    background: var(--MENU-SEARCH-BG-color);\n}\n#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {\n    background: var(--MENU-SECTIONS-ACTIVE-BG-color);\n}\n#sidebar .searchbox * {\n    color: var(--MENU-SEARCH-BOX-ICONS-color);\n}\n\n#sidebar a {\n    color: var(--MENU-SECTIONS-LINK-color);\n}\n\n#sidebar a:hover {\n    color: var(--MENU-SECTIONS-LINK-HOVER-color);\n}\n\n#sidebar ul li.active > a {\n    background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);\n    color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;\n}\n\n#sidebar hr {\n    border-color: var(--MENU-SECTION-HR-color);\n}\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/css/theme-red.css",
    "content": "\n:root{\n    \n    --MAIN-TEXT-color:#323232; /* Color of text by default */\n    --MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */\n    --MAIN-LINK-color:#f31c1c; /* Color of links */\n    --MAIN-LINK-HOVER-color:#d01616; /* Color of hovered links */\n    --MAIN-ANCHOR-color: #f31c1c; /* color of anchors on titles */\n\n    --MENU-HEADER-BG-color:#dc1010; /* Background color of menu header */\n    --MENU-HEADER-BORDER-color:#e23131; /*Color of menu header border */ \n\n    --MENU-SEARCH-BG-color:#b90000; /* Search field background color (by default borders + icons) */\n    --MENU-SEARCH-BOX-color: #ef2020; /* Override search field border color */\n    --MENU-SEARCH-BOX-ICONS-color: #fda1a1; /* Override search field icons color */\n\n    --MENU-SECTIONS-ACTIVE-BG-color:#2b2020; /* Background color of the active section and its childs */\n    --MENU-SECTIONS-BG-color:#312525; /* Background color of other sections */\n    --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */\n    --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6;  /* Color of links in menu, when hovered */\n    --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */\n    --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */\n    \n    --MENU-VISITED-color: #ff3333; /* Color of 'page visited' icons in menu */\n    --MENU-SECTION-HR-color: #2b2020; /* Color of <hr> separator in menu */\n    \n}\n\nbody {\n    color: var(--MAIN-TEXT-color) !important;\n}\n\ntextarea:focus, input[type=\"email\"]:focus, input[type=\"number\"]:focus, input[type=\"password\"]:focus, input[type=\"search\"]:focus, input[type=\"tel\"]:focus, input[type=\"text\"]:focus, input[type=\"url\"]:focus, input[type=\"color\"]:focus, input[type=\"date\"]:focus, input[type=\"datetime\"]:focus, input[type=\"datetime-local\"]:focus, input[type=\"month\"]:focus, input[type=\"time\"]:focus, input[type=\"week\"]:focus, select[multiple=multiple]:focus {\n    border-color: none;\n    box-shadow: none;\n}\n\nh2, h3, h4, h5 {\n    color: var(--MAIN-TITLES-TEXT-color) !important;\n}\n\na {\n    color: var(--MAIN-LINK-color);\n}\n\n.anchor {\n    color: var(--MAIN-ANCHOR-color);\n}\n\na:hover {\n    color: var(--MAIN-LINK-HOVER-color);\n}\n\n#sidebar ul li.visited > a .read-icon {\n\tcolor: var(--MENU-VISITED-color);\n}\n\n#body a.highlight:after {\n    display: block;\n    content: \"\";\n    height: 1px;\n    width: 0%;\n    -webkit-transition: width 0.5s ease;\n    -moz-transition: width 0.5s ease;\n    -ms-transition: width 0.5s ease;\n    transition: width 0.5s ease;\n    background-color: var(--MAIN-LINK-HOVER-color);\n}\n#sidebar {\n\tbackground-color: var(--MENU-SECTIONS-BG-color);\n}\n#sidebar #header-wrapper {\n    background: var(--MENU-HEADER-BG-color);\n    color: var(--MENU-SEARCH-BOX-color);\n    border-color: var(--MENU-HEADER-BORDER-color);\n}\n#sidebar .searchbox {\n\tborder-color: var(--MENU-SEARCH-BOX-color);\n    background: var(--MENU-SEARCH-BG-color);\n}\n#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {\n    background: var(--MENU-SECTIONS-ACTIVE-BG-color);\n}\n#sidebar .searchbox * {\n    color: var(--MENU-SEARCH-BOX-ICONS-color);\n}\n\n#sidebar a {\n    color: var(--MENU-SECTIONS-LINK-color);\n}\n\n#sidebar a:hover {\n    color: var(--MENU-SECTIONS-LINK-HOVER-color);\n}\n\n#sidebar ul li.active > a {\n    background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);\n    color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;\n}\n\n#sidebar hr {\n    border-color: var(--MENU-SECTION-HR-color);\n}\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/css/theme.css",
    "content": "@charset \"UTF-8\";\n#top-github-link, #body #breadcrumbs {\n    position: relative;\n    top: 50%;\n    -webkit-transform: translateY(-50%);\n    -moz-transform: translateY(-50%);\n    -o-transform: translateY(-50%);\n    -ms-transform: translateY(-50%);\n    transform: translateY(-50%);\n}\n.button, .button-secondary {\n    display: inline-block;\n    padding: 7px 12px;\n}\n.button:active, .button-secondary:active {\n    margin: 2px 0 -2px 0;\n}\n@font-face {\n    font-family: 'Novacento Sans Wide';\n    src: url(\"../fonts/Novecentosanswide-UltraLight-webfont.eot\");\n    src: url(\"../fonts/Novecentosanswide-UltraLight-webfont.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/Novecentosanswide-UltraLight-webfont.woff2\") format(\"woff2\"), url(\"../fonts/Novecentosanswide-UltraLight-webfont.woff\") format(\"woff\"), url(\"../fonts/Novecentosanswide-UltraLight-webfont.ttf\") format(\"truetype\"), url(\"../fonts/Novecentosanswide-UltraLight-webfont.svg#novecento_sans_wideultralight\") format(\"svg\");\n    font-style: normal;\n    font-weight: 200;\n}\n@font-face {\n    font-family: 'Work Sans';\n    font-style: normal;\n    font-weight: 300;\n    src: url(\"../fonts/Work_Sans_300.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/Work_Sans_300.woff\") format(\"woff\"), url(\"../fonts/Work_Sans_300.woff2\") format(\"woff2\"), url(\"../fonts/Work_Sans_300.svg#WorkSans\") format(\"svg\"), url(\"../fonts/Work_Sans_300.ttf\") format(\"truetype\");\n}\n@font-face {\n    font-family: 'Work Sans';\n    font-style: normal;\n    font-weight: 500;\n    src: url(\"../fonts/Work_Sans_500.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/Work_Sans_500.woff\") format(\"woff\"), url(\"../fonts/Work_Sans_500.woff2\") format(\"woff2\"), url(\"../fonts/Work_Sans_500.svg#WorkSans\") format(\"svg\"), url(\"../fonts/Work_Sans_500.ttf\") format(\"truetype\");\n}\nbody {\n    background: #fff;\n    color: #777;\n}\nbody #chapter h1 {\n    font-size: 3.5rem;\n}\n@media only all and (min-width: 48em) and (max-width: 59.938em) {\n    body #chapter h1 {\n        font-size: 3rem;\n    }\n}\n@media only all and (max-width: 47.938em) {\n    body #chapter h1 {\n        font-size: 2rem;\n    }\n}\na {\n    color: #00bdf3;\n}\na:hover {\n    color: #0082a7;\n}\npre {\n    position: relative;\n    color: #ffffff;\n}\n.bg {\n    background: #fff;\n    border: 1px solid #eaeaea;\n}\nb, strong, label, th {\n    font-weight: 600;\n}\n.default-animation, #header #logo-svg, #header #logo-svg path, #sidebar, #sidebar ul, #body, #body .padding, #body .nav {\n    -webkit-transition: all 0.5s ease;\n    -moz-transition: all 0.5s ease;\n    transition: all 0.5s ease;\n}\n#grav-logo {\n    max-width: 60%;\n}\n#grav-logo path {\n    fill: #fff !important;\n}\n#sidebar {\n    font-weight: 300 !important;\n}\nfieldset {\n    border: 1px solid #ddd;\n}\ntextarea, input[type=\"email\"], input[type=\"number\"], input[type=\"password\"], input[type=\"search\"], input[type=\"tel\"], input[type=\"text\"], input[type=\"url\"], input[type=\"color\"], input[type=\"date\"], input[type=\"datetime\"], input[type=\"datetime-local\"], input[type=\"month\"], input[type=\"time\"], input[type=\"week\"], select[multiple=multiple] {\n    background-color: white;\n    border: 1px solid #ddd;\n    box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06);\n}\ntextarea:hover, input[type=\"email\"]:hover, input[type=\"number\"]:hover, input[type=\"password\"]:hover, input[type=\"search\"]:hover, input[type=\"tel\"]:hover, input[type=\"text\"]:hover, input[type=\"url\"]:hover, input[type=\"color\"]:hover, input[type=\"date\"]:hover, input[type=\"datetime\"]:hover, input[type=\"datetime-local\"]:hover, input[type=\"month\"]:hover, input[type=\"time\"]:hover, input[type=\"week\"]:hover, select[multiple=multiple]:hover {\n    border-color: #c4c4c4;\n}\ntextarea:focus, input[type=\"email\"]:focus, input[type=\"number\"]:focus, input[type=\"password\"]:focus, input[type=\"search\"]:focus, input[type=\"tel\"]:focus, input[type=\"text\"]:focus, input[type=\"url\"]:focus, input[type=\"color\"]:focus, input[type=\"date\"]:focus, input[type=\"datetime\"]:focus, input[type=\"datetime-local\"]:focus, input[type=\"month\"]:focus, input[type=\"time\"]:focus, input[type=\"week\"]:focus, select[multiple=multiple]:focus {\n    border-color: #00bdf3;\n    box-shadow: inset 0 1px 3px rgba(0,0,0,.06),0 0 5px rgba(0,169,218,.7)\n}\n#header-wrapper {\n    background: #8451a1;\n    color: #fff;\n    text-align: center;\n    border-bottom: 4px solid #9c6fb6;\n    padding: 1rem;\n}\n#header a {\n    display: inline-block;\n}\n#header #logo-svg {\n    width: 8rem;\n    height: 2rem;\n}\n#header #logo-svg path {\n    fill: #fff;\n}\n.searchbox {\n    margin-top: 1rem;\n    position: relative;\n    border: 1px solid #915eae;\n    background: #764890;\n    border-radius: 4px;\n}\n.searchbox label {\n    color: rgba(255, 255, 255, 0.8);\n    position: absolute;\n    left: 10px;\n    top: 3px;\n}\n.searchbox span {\n    color: rgba(255, 255, 255, 0.6);\n    position: absolute;\n    right: 10px;\n    top: 3px;\n    cursor: pointer;\n}\n.searchbox span:hover {\n    color: rgba(255, 255, 255, 0.9);\n}\n.searchbox input {\n    display: inline-block;\n    color: #fff;\n    width: 100%;\n    height: 30px;\n    background: transparent;\n    border: 0;\n    padding: 0 25px 0 30px;\n    margin: 0;\n    font-weight: 300;\n}\n.searchbox input::-webkit-input-placeholder {\n    color: rgba(255, 255, 255, 0.6);\n}\n.searchbox input::-moz-placeholder {\n    color: rgba(255, 255, 255, 0.6);\n}\n.searchbox input:-moz-placeholder {\n    color: rgba(255, 255, 255, 0.6);\n}\n.searchbox input:-ms-input-placeholder {\n    color: rgba(255, 255, 255, 0.6);\n}\n#sidebar-toggle-span {\n    display: none;\n}\n@media only all and (max-width: 47.938em) {\n    #sidebar-toggle-span {\n        display: inline;\n    }\n}\n#sidebar {\n    background-color: #322A38;\n    position: fixed;\n    top: 0;\n    width: 300px;\n    bottom: 0;\n    left: 0;\n    font-weight: 400;\n    font-size: 15px;\n}\n#sidebar a {\n    color: #ccc;\n}\n#sidebar a:hover {\n    color: #e6e6e6;\n}\n#sidebar a.subtitle {\n    color: rgba(204, 204, 204, 0.6);\n}\n#sidebar hr {\n    border-bottom: 1px solid #2a232f;\n}\n#sidebar a.padding {\n    padding: 0 1rem;\n}\n#sidebar h5 {\n    margin: 2rem 0 0;\n    position: relative;\n    line-height: 2;\n}\n#sidebar h5 a {\n    display: block;\n    margin-left: 0;\n    margin-right: 0;\n    padding-left: 1rem;\n    padding-right: 1rem;\n}\n#sidebar h5 i {\n    color: rgba(204, 204, 204, 0.6);\n    position: absolute;\n    right: 0.6rem;\n    top: 0.7rem;\n    font-size: 80%;\n}\n#sidebar h5.parent a {\n    background: #201b24;\n    color: #d9d9d9 !important;\n}\n#sidebar h5.active a {\n    background: #fff;\n    color: #777 !important;\n}\n#sidebar h5.active i {\n    color: #777 !important;\n}\n#sidebar h5 + ul.topics {\n    display: none;\n    margin-top: 0;\n}\n#sidebar h5.parent + ul.topics, #sidebar h5.active + ul.topics {\n    display: block;\n}\n#sidebar ul {\n    list-style: none;\n    padding: 0;\n    margin: 0;\n}\n#sidebar ul.searched a {\n    color: #999999;\n}\n#sidebar ul.searched .search-match a {\n    color: #e6e6e6;\n}\n#sidebar ul.searched .search-match a:hover {\n    color: white;\n}\n#sidebar ul.topics {\n    margin: 0 1rem;\n}\n#sidebar ul.topics.searched ul {\n    display: block;\n}\n#sidebar ul.topics ul {\n    display: none;\n    padding-bottom: 1rem;\n}\n#sidebar ul.topics ul ul {\n    padding-bottom: 0;\n}\n#sidebar ul.topics li.parent>ul, #sidebar ul.topics > li.active>ul {\n    display: block;\n}\n#sidebar ul.topics > li > a {\n    line-height: 2rem;\n    font-size: 1.1rem;\n}\n#sidebar ul.topics > li > a b {\n    opacity: 0.5;\n    font-weight: normal;\n}\n#sidebar ul.topics > li > a .fa {\n    margin-top: 9px;\n}\n#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {\n    background: #251f29;\n    margin-left: -1rem;\n    margin-right: -1rem;\n    padding-left: 1rem;\n    padding-right: 1rem;\n}\n#sidebar ul li.active > a {\n    background: #fff;\n    color: #777 !important;\n    margin-left: -1rem;\n    margin-right: -1rem;\n    padding-left: 1rem;\n    padding-right: 1rem;\n}\n#sidebar ul li {\n    padding: 0;\n}\n#sidebar ul li.visited + span {\n    margin-right: 16px;\n}\n#sidebar ul li a {\n    display: block;\n    padding: 2px 0;\n}\n#sidebar ul li a span {\n    text-overflow: ellipsis;\n    overflow: hidden;\n    white-space: nowrap;\n    display: block;\n}\n#sidebar ul li > a {\n    padding: 4px 0;\n}\n#sidebar ul li.visited > a .read-icon {\n    color: #9c6fb6;\n    display: inline;\n}\n#sidebar ul li li {\n    padding-left: 1rem;\n    text-indent: 0.2rem;\n}\n#main {\n    background: #f7f7f7;\n    margin: 0 0 1.563rem 0;\n}\n#body {\n    position: relative;\n    margin-left: 300px;\n    min-height: 100%;\n}\n#body img, #body .video-container {\n    margin: 3rem auto;\n    display: block;\n    text-align: center;\n}\n#body img.border, #body .video-container.border {\n    border: 2px solid #e6e6e6 !important;\n    padding: 2px;\n}\n#body img.shadow, #body .video-container.shadow {\n    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);\n}\n#body img.inline {\n    display: inline !important;\n    margin: 0 !important;\n    vertical-align: bottom;\n}\n#body .bordered {\n    border: 1px solid #ccc;\n}\n#body .padding {\n    padding: 3rem 6rem;\n}\n@media only all and (max-width: 59.938em) {\n    #body .padding {\n        position: static;\n        padding: 15px 3rem;\n    }\n}\n@media only all and (max-width: 47.938em) {\n    #body .padding {\n        padding: 5px 1rem;\n    }\n}\n#body h1 + hr {\n    margin-top: -1.7rem;\n    margin-bottom: 3rem;\n}\n@media only all and (max-width: 59.938em) {\n    #body #navigation {\n        position: static;\n        margin-right: 0 !important;\n        width: 100%;\n        display: table;\n    }\n}\n#body .nav {\n    position: fixed;\n    top: 0;\n    bottom: 0;\n    width: 4rem;\n    font-size: 50px;\n    height: 100%;\n    cursor: pointer;\n    display: table;\n    text-align: center;\n}\n#body .nav > i {\n    display: table-cell;\n    vertical-align: middle;\n    text-align: center;\n}\n@media only all and (max-width: 59.938em) {\n    #body .nav {\n        display: table-cell;\n        position: static;\n        top: auto;\n        width: 50%;\n        text-align: center;\n        height: 100px;\n        line-height: 100px;\n        padding-top: 0;\n    }\n    #body .nav > i {\n        display: inline-block;\n    }\n}\n#body .nav:hover {\n    background: #F6F6F6;\n}\n#body .nav.nav-pref {\n    left: 0;\n}\n#body .nav.nav-next {\n    right: 0;\n}\n#body-inner {\n    margin-bottom: 5rem;\n}\n#chapter {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    height: 100%;\n    padding: 2rem 0;\n}\n#chapter #body-inner {\n    padding-bottom: 3rem;\n    max-width: 80%;\n}\n#chapter h3 {\n    font-family: \"Work Sans\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    font-weight: 300;\n    text-align: center;\n}\n#chapter h1 {\n    font-size: 5rem;\n    border-bottom: 4px solid #F0F2F4;\n}\n#chapter p {\n    text-align: center;\n    /* font-size: 1.2rem; */\n}\n#footer {\n    padding: 3rem 1rem;\n    color: #b3b3b3;\n    font-size: 13px;\n}\n#footer p {\n    margin: 0;\n}\nbody {\n    font-family: \"Work Sans\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    font-weight: 300;\n    line-height: 1.6;\n    font-size: 18px !important;\n}\nh2, h3, h4, h5, h6 {\n    font-family: \"Work Sans\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    text-rendering: optimizeLegibility;\n    color: #5e5e5e;\n    font-weight: 400;\n    letter-spacing: -1px;\n}\nh1 {\n    font-family: \"Novacento Sans Wide\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    text-align: center;\n    text-transform: uppercase;\n    color: #222;\n    font-weight: 200;\n}\nblockquote {\n    border-left: 10px solid #F0F2F4;\n}\nblockquote p {\n    font-size: 1.1rem;\n    color: #999;\n}\nblockquote cite {\n    display: block;\n    text-align: right;\n    color: #666;\n    font-size: 1.2rem;\n}\ndiv.notices {\n    margin: 2rem 0;\n    position: relative;\n}\ndiv.notices p {\n    padding: 15px;\n    display: block;\n    font-size: 1rem;\n    margin-top: 0rem;\n    margin-bottom: 0rem;\n    color: #666;\n}\ndiv.notices p:first-child:before {\n    position: absolute;\n    top: 2px;\n    color: #fff;\n    font-family: FontAwesome;\n    content: '';\n    left: 10px;\n}\ndiv.notices p:first-child:after {\n    position: absolute;\n    top: 2px;\n    color: #fff;\n    left: 2rem;\n}\ndiv.notices.info p {\n    border-top: 30px solid #F0B37E;\n    background: #FFF2DB;\n}\ndiv.notices.info p:first-child:after {\n    content: 'Info';\n}\ndiv.notices.warning p {\n    border-top: 30px solid rgba(217, 83, 79, 0.8);\n    background: #FAE2E2;\n}\ndiv.notices.warning p:first-child:after {\n    content: 'Warning';\n}\ndiv.notices.note p {\n    border-top: 30px solid #6AB0DE;\n    background: #E7F2FA;\n}\ndiv.notices.note p:first-child:after {\n    content: 'Note';\n}\ndiv.notices.tip p {\n    border-top: 30px solid rgba(92, 184, 92, 0.8);\n    background: #E6F9E6;\n}\ndiv.notices.tip p:first-child:after {\n    content: 'Tip';\n}\n\n/* attachments shortcode */\n\nsection.attachments {\n    margin: 2rem 0;\n    position: relative;\n}\n\nsection.attachments label {\n    font-weight: 400;\n    padding-left: 0.5em;\n    padding-top: 0.2em;\n    padding-bottom: 0.2em;\n    margin: 0;\n}\n\nsection.attachments .attachments-files {\n    padding: 15px;\n    display: block;\n    font-size: 1rem;\n    margin-top: 0rem;\n    margin-bottom: 0rem;\n    color: #666;\n}\n\nsection.attachments.orange label {\n    color: #fff;\n    background: #F0B37E;\n}\n\nsection.attachments.orange .attachments-files {\n    background: #FFF2DB;\n}\n\nsection.attachments.green label {\n    color: #fff;\n    background: rgba(92, 184, 92, 0.8);\n}\n\nsection.attachments.green .attachments-files {\n    background: #E6F9E6;\n}\n\nsection.attachments.blue label {\n    color: #fff;\n    background: #6AB0DE;\n}\n\nsection.attachments.blue .attachments-files {\n    background: #E7F2FA;\n}\n\nsection.attachments.grey label {\n    color: #fff;\n    background: #505d65;\n}\n\nsection.attachments.grey .attachments-files {\n    background: #f4f4f4;\n}\n\n/* Children shortcode */\n\n/* Children shortcode */\n.children p {\n    font-size: small;\n    margin-top: 0px;\n    padding-top: 0px;\n    margin-bottom:  0px;\n    padding-bottom: 0px;\n}\n.children-li p {\n    font-size: small;\n    font-style: italic;\n\n}\n.children-h2 p, .children-h3 p {\n    font-size: small;\n    margin-top: 0px;\n    padding-top: 0px;\n    margin-bottom:  0px;\n    padding-bottom: 0px;\n}\n.children h3,.children h2 {\n    margin-bottom: 0px;\n    margin-top: 5px;\n}\n\ncode, kbd, pre, samp {\n    font-family: \"Consolas\", menlo, monospace;\n    font-size: 92%;\n}\ncode {\n    border-radius: 2px;\n    white-space: nowrap;\n    color: #5e5e5e;\n    background: #FFF7DD;\n    border: 1px solid #fbf0cb;\n    padding: 0px 2px;\n}\ncode + .copy-to-clipboard {\n    margin-left: -1px;\n    border-left: 0 !important;\n    font-size: inherit !important;\n    vertical-align: middle;\n    height: 21px;\n    top: 0;\n}\npre {\n    padding: 1rem;\n    margin: 2rem 0;\n    background: #1d1f21;\n    border: 0;\n    border-radius: 2px;\n    line-height: 1.15;\n}\npre code {\n    color: whitesmoke;\n    background: inherit;\n    white-space: inherit;\n    border: 0;\n    padding: 0;\n    margin: 0;\n    font-size: 15px;\n}\nhr {\n    border-bottom: 4px solid #F0F2F4;\n}\n.page-title {\n    margin-top: -25px;\n    padding: 25px;\n    float: left;\n    clear: both;\n    background: #9c6fb6;\n    color: #fff;\n}\n#body a.anchor-link {\n    color: #ccc;\n}\n#body a.anchor-link:hover {\n    color: #9c6fb6;\n}\n#body-inner .tabs-wrapper.ui-theme-badges {\n    background: #1d1f21;\n}\n#body-inner .tabs-wrapper.ui-theme-badges .tabs-nav li {\n    font-size: 0.9rem;\n    text-transform: uppercase;\n}\n#body-inner .tabs-wrapper.ui-theme-badges .tabs-nav li a {\n    background: #35393c;\n}\n#body-inner .tabs-wrapper.ui-theme-badges .tabs-nav li.current a {\n    background: #4d5257;\n}\n#body-inner pre {\n    white-space: pre-wrap;\n}\n.tabs-wrapper pre {\n    margin: 1rem 0;\n    border: 0;\n    padding: 0;\n    background: inherit;\n}\ntable {\n    border: 1px solid #eaeaea;\n    table-layout: auto;\n}\nth {\n    background: #f7f7f7;\n    padding: 0.5rem;\n}\ntd {\n    padding: 0.5rem;\n    border: 1px solid #eaeaea;\n}\n.button {\n    background: #9c6fb6;\n    color: #fff;\n    box-shadow: 0 3px 0 #00a5d4;\n}\n.button:hover {\n    background: #00a5d4;\n    box-shadow: 0 3px 0 #008db6;\n    color: #fff;\n}\n.button:active {\n    box-shadow: 0 1px 0 #008db6;\n}\n.button-secondary {\n    background: #F8B450;\n    color: #fff;\n    box-shadow: 0 3px 0 #f7a733;\n}\n.button-secondary:hover {\n    background: #f7a733;\n    box-shadow: 0 3px 0 #f69b15;\n    color: #fff;\n}\n.button-secondary:active {\n    box-shadow: 0 1px 0 #f69b15;\n}\n.bullets {\n    margin: 1.7rem 0;\n    margin-left: -0.85rem;\n    margin-right: -0.85rem;\n    overflow: auto;\n}\n.bullet {\n    float: left;\n    padding: 0 0.85rem;\n}\n.two-column-bullet {\n    width: 50%;\n}\n@media only all and (max-width: 47.938em) {\n    .two-column-bullet {\n        width: 100%;\n    }\n}\n.three-column-bullet {\n    width: 33.33333%;\n}\n@media only all and (max-width: 47.938em) {\n    .three-column-bullet {\n        width: 100%;\n    }\n}\n.four-column-bullet {\n    width: 25%;\n}\n@media only all and (max-width: 47.938em) {\n    .four-column-bullet {\n        width: 100%;\n    }\n}\n.bullet-icon {\n    float: left;\n    background: #9c6fb6;\n    padding: 0.875rem;\n    width: 3.5rem;\n    height: 3.5rem;\n    border-radius: 50%;\n    color: #fff;\n    font-size: 1.75rem;\n    text-align: center;\n}\n.bullet-icon-1 {\n    background: #9c6fb6;\n}\n.bullet-icon-2 {\n    background: #00f3d8;\n}\n.bullet-icon-3 {\n    background: #e6f300;\n}\n.bullet-content {\n    margin-left: 4.55rem;\n}\n.tooltipped {\n    position: relative;\n}\n.tooltipped:after {\n    position: absolute;\n    z-index: 1000000;\n    display: none;\n    padding: 5px 8px;\n    font: normal normal 11px/1.5 \"Work Sans\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    color: #fff;\n    text-align: center;\n    text-decoration: none;\n    text-shadow: none;\n    text-transform: none;\n    letter-spacing: normal;\n    word-wrap: break-word;\n    white-space: pre;\n    pointer-events: none;\n    content: attr(aria-label);\n    background: rgba(0, 0, 0, 0.8);\n    border-radius: 3px;\n    -webkit-font-smoothing: subpixel-antialiased;\n}\n.tooltipped:before {\n    position: absolute;\n    z-index: 1000001;\n    display: none;\n    width: 0;\n    height: 0;\n    color: rgba(0, 0, 0, 0.8);\n    pointer-events: none;\n    content: \"\";\n    border: 5px solid transparent;\n}\n.tooltipped:hover:before, .tooltipped:hover:after, .tooltipped:active:before, .tooltipped:active:after, .tooltipped:focus:before, .tooltipped:focus:after {\n    display: inline-block;\n    text-decoration: none;\n}\n.tooltipped-s:after, .tooltipped-se:after, .tooltipped-sw:after {\n    top: 100%;\n    right: 50%;\n    margin-top: 5px;\n}\n.tooltipped-s:before, .tooltipped-se:before, .tooltipped-sw:before {\n    top: auto;\n    right: 50%;\n    bottom: -5px;\n    margin-right: -5px;\n    border-bottom-color: rgba(0, 0, 0, 0.8);\n}\n.tooltipped-se:after {\n    right: auto;\n    left: 50%;\n    margin-left: -15px;\n}\n.tooltipped-sw:after {\n    margin-right: -15px;\n}\n.tooltipped-n:after, .tooltipped-ne:after, .tooltipped-nw:after {\n    right: 50%;\n    bottom: 100%;\n    margin-bottom: 5px;\n}\n.tooltipped-n:before, .tooltipped-ne:before, .tooltipped-nw:before {\n    top: -5px;\n    right: 50%;\n    bottom: auto;\n    margin-right: -5px;\n    border-top-color: rgba(0, 0, 0, 0.8);\n}\n.tooltipped-ne:after {\n    right: auto;\n    left: 50%;\n    margin-left: -15px;\n}\n.tooltipped-nw:after {\n    margin-right: -15px;\n}\n.tooltipped-s:after, .tooltipped-n:after {\n    transform: translateX(50%);\n}\n.tooltipped-w:after {\n    right: 100%;\n    bottom: 50%;\n    margin-right: 5px;\n    transform: translateY(50%);\n}\n.tooltipped-w:before {\n    top: 50%;\n    bottom: 50%;\n    left: -5px;\n    margin-top: -5px;\n    border-left-color: rgba(0, 0, 0, 0.8);\n}\n.tooltipped-e:after {\n    bottom: 50%;\n    left: 100%;\n    margin-left: 5px;\n    transform: translateY(50%);\n}\n.tooltipped-e:before {\n    top: 50%;\n    right: -5px;\n    bottom: 50%;\n    margin-top: -5px;\n    border-right-color: rgba(0, 0, 0, 0.8);\n}\n.highlightable {\n    padding: 1rem 0 1rem;\n    overflow: auto;\n    position: relative;\n}\n.hljs::selection, .hljs span::selection {\n    background: #b7b7b7;\n}\n.lightbox-active #body {\n    overflow: visible;\n}\n.lightbox-active #body .padding {\n    overflow: visible;\n}\n#github-contrib i {\n    vertical-align: middle;\n}\n.featherlight img {\n    margin: 0 !important;\n}\n.lifecycle #body-inner ul {\n    list-style: none;\n    margin: 0;\n    padding: 2rem 0 0;\n    position: relative;\n}\n.lifecycle #body-inner ol {\n    margin: 1rem 0 1rem 0;\n    padding: 2rem;\n    position: relative;\n}\n.lifecycle #body-inner ol li {\n    margin-left: 1rem;\n}\n.lifecycle #body-inner ol strong, .lifecycle #body-inner ol label, .lifecycle #body-inner ol th {\n    text-decoration: underline;\n}\n.lifecycle #body-inner ol ol {\n    margin-left: -1rem;\n}\n.lifecycle #body-inner h3[class*='level'] {\n    font-size: 20px;\n    position: absolute;\n    margin: 0;\n    padding: 4px 10px;\n    right: 0;\n    z-index: 1000;\n    color: #fff;\n    background: #1ABC9C;\n}\n.lifecycle #body-inner ol h3 {\n    margin-top: 1rem !important;\n    right: 2rem !important;\n}\n.lifecycle #body-inner .level-1 + ol {\n    background: #f6fefc;\n    border: 4px solid #1ABC9C;\n    color: #16A085;\n}\n.lifecycle #body-inner .level-1 + ol h3 {\n    background: #2ECC71;\n}\n.lifecycle #body-inner .level-2 + ol {\n    background: #f7fdf9;\n    border: 4px solid #2ECC71;\n    color: #27AE60;\n}\n.lifecycle #body-inner .level-2 + ol h3 {\n    background: #3498DB;\n}\n.lifecycle #body-inner .level-3 + ol {\n    background: #f3f9fd;\n    border: 4px solid #3498DB;\n    color: #2980B9;\n}\n.lifecycle #body-inner .level-3 + ol h3 {\n    background: #34495E;\n}\n.lifecycle #body-inner .level-4 + ol {\n    background: #e4eaf0;\n    border: 4px solid #34495E;\n    color: #2C3E50;\n}\n.lifecycle #body-inner .level-4 + ol h3 {\n    background: #34495E;\n}\n#top-bar {\n    background: #F6F6F6;\n    border-radius: 2px;\n    padding: 0 1rem;\n    height: 0;\n    min-height: 3rem;\n}\n#top-github-link {\n    position: relative;\n    z-index: 1;\n    float: right;\n    display: block;\n}\n#body #breadcrumbs {\n    height: auto;\n    margin-bottom: 0;\n    padding-left: 0;\n    line-height: 1.4;\n    overflow: hidden;\n    white-space: nowrap;\n    text-overflow: ellipsis;\n    width: 70%;\n    display: inline-block;\n    float: left;\n}\n#body #breadcrumbs span {\n    padding: 0 0.1rem;\n}\n@media only all and (max-width: 59.938em) {\n    #sidebar {\n        width: 230px;\n    }\n    #body {\n        margin-left: 230px;\n    }\n}\n@media only all and (max-width: 47.938em) {\n    #sidebar {\n        width: 230px;\n        left: -230px;\n    }\n    #body {\n        margin-left: 0;\n        width: 100%;\n    }\n    .sidebar-hidden {\n        overflow: hidden;\n    }\n    .sidebar-hidden #sidebar {\n        left: 0;\n    }\n    .sidebar-hidden #body {\n        margin-left: 230px;\n        overflow: hidden;\n    }\n    .sidebar-hidden #overlay {\n        position: absolute;\n        left: 0;\n        right: 0;\n        top: 0;\n        bottom: 0;\n        z-index: 10;\n        background: rgba(255, 255, 255, 0.5);\n        cursor: pointer;\n    }\n}\n.copy-to-clipboard {\n    background-image: url(../images/clippy.svg);\n    background-position: 50% 50%;\n    background-size: 16px 16px;\n    background-repeat: no-repeat;\n    width: 27px;\n    height: 1.45rem;\n    top: -1px;\n    display: inline-block;\n    vertical-align: middle;\n    position: relative;\n    color: #5e5e5e;\n    background-color: #FFF7DD;\n    margin-left: -.2rem;\n    cursor: pointer;\n    border-radius: 0 2px 2px 0;\n    margin-bottom: 1px;\n}\n.copy-to-clipboard:hover {\n    background-color: #E8E2CD;\n}\npre .copy-to-clipboard {\n    position: absolute;\n    right: 4px;\n    top: 4px;\n    background-color: #4d5257;\n    color: #ccc;\n    border-radius: 2px;\n}\npre .copy-to-clipboard:hover {\n    background-color: #656c72;\n    color: #fff;\n}\n.parent-element {\n    -webkit-transform-style: preserve-3d;\n    -moz-transform-style: preserve-3d;\n    transform-style: preserve-3d;\n}\n\n#sidebar ul.topics > li > a .read-icon {\n    margin-top: 9px;\n}\n\n#sidebar ul {\n    list-style: none;\n    padding: 0;\n    margin: 0;\n}\n\n#sidebar #shortcuts li {\n    padding: 2px 0;\n    list-style: none;\n}\n\n#sidebar ul li .read-icon {\n    display: none;\n    float: right;\n    font-size: 13px;\n    min-width: 16px;\n    margin: 4px 0 0 0;\n    text-align: right;\n}\n#sidebar ul li.visited > a .read-icon {\n    color: #00bdf3;\n    display: inline;\n}\n\n#sidebar #shortcuts h3 {\n    font-family: \"Novacento Sans Wide\", \"Helvetica\", \"Tahoma\", \"Geneva\", \"Arial\", sans-serif;\n    color: white ;\n    margin-top:1rem;\n    padding-left: 1rem;\n}\n\n#searchResults {\n    text-align: left;\n}\n\n/*# sourceMappingURL=theme.css.map */\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/js/auto-complete.js",
    "content": "/*\n    JavaScript autoComplete v1.0.4\n    Copyright (c) 2014 Simon Steinberger / Pixabay\n    GitHub: https://github.com/Pixabay/JavaScript-autoComplete\n    License: http://www.opensource.org/licenses/mit-license.php\n*/\n\nvar autoComplete = (function(){\n    // \"use strict\";\n    function autoComplete(options){\n        if (!document.querySelector) return;\n\n        // helpers\n        function hasClass(el, className){ return el.classList ? el.classList.contains(className) : new RegExp('\\\\b'+ className+'\\\\b').test(el.className); }\n\n        function addEvent(el, type, handler){\n            if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler);\n        }\n        function removeEvent(el, type, handler){\n            // if (el.removeEventListener) not working in IE11\n            if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler);\n        }\n        function live(elClass, event, cb, context){\n            addEvent(context || document, event, function(e){\n                var found, el = e.target || e.srcElement;\n                while (el && !(found = hasClass(el, elClass))) el = el.parentElement;\n                if (found) cb.call(el, e);\n            });\n        }\n\n        var o = {\n            selector: 0,\n            source: 0,\n            minChars: 3,\n            delay: 150,\n            offsetLeft: 0,\n            offsetTop: 1,\n            cache: 1,\n            menuClass: '',\n            renderItem: function (item, search){\n                // escape special characters\n                search = search.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n                var re = new RegExp(\"(\" + search.split(' ').join('|') + \")\", \"gi\");\n                return '<div class=\"autocomplete-suggestion\" data-val=\"' + item + '\">' + item.replace(re, \"<b>$1</b>\") + '</div>';\n            },\n            onSelect: function(e, term, item){}\n        };\n        for (var k in options) { if (options.hasOwnProperty(k)) o[k] = options[k]; }\n\n        // init\n        var elems = typeof o.selector == 'object' ? [o.selector] : document.querySelectorAll(o.selector);\n        for (var i=0; i<elems.length; i++) {\n            var that = elems[i];\n\n            // create suggestions container \"sc\"\n            that.sc = document.createElement('div');\n            that.sc.className = 'autocomplete-suggestions '+o.menuClass;\n\n            that.autocompleteAttr = that.getAttribute('autocomplete');\n            that.setAttribute('autocomplete', 'off');\n            that.cache = {};\n            that.last_val = '';\n\n            that.updateSC = function(resize, next){\n                var rect = that.getBoundingClientRect();\n                that.sc.style.left = Math.round(rect.left + (window.pageXOffset || document.documentElement.scrollLeft) + o.offsetLeft) + 'px';\n                that.sc.style.top = Math.round(rect.bottom + (window.pageYOffset || document.documentElement.scrollTop) + o.offsetTop) + 'px';\n                that.sc.style.width = Math.round(rect.right - rect.left) + 'px'; // outerWidth\n                if (!resize) {\n                    that.sc.style.display = 'block';\n                    if (!that.sc.maxHeight) { that.sc.maxHeight = parseInt((window.getComputedStyle ? getComputedStyle(that.sc, null) : that.sc.currentStyle).maxHeight); }\n                    if (!that.sc.suggestionHeight) that.sc.suggestionHeight = that.sc.querySelector('.autocomplete-suggestion').offsetHeight;\n                    if (that.sc.suggestionHeight)\n                        if (!next) that.sc.scrollTop = 0;\n                        else {\n                            var scrTop = that.sc.scrollTop, selTop = next.getBoundingClientRect().top - that.sc.getBoundingClientRect().top;\n                            if (selTop + that.sc.suggestionHeight - that.sc.maxHeight > 0)\n                                that.sc.scrollTop = selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight;\n                            else if (selTop < 0)\n                                that.sc.scrollTop = selTop + scrTop;\n                        }\n                }\n            }\n            addEvent(window, 'resize', that.updateSC);\n            document.body.appendChild(that.sc);\n\n            live('autocomplete-suggestion', 'mouseleave', function(e){\n                var sel = that.sc.querySelector('.autocomplete-suggestion.selected');\n                if (sel) setTimeout(function(){ sel.className = sel.className.replace('selected', ''); }, 20);\n            }, that.sc);\n\n            live('autocomplete-suggestion', 'mouseover', function(e){\n                var sel = that.sc.querySelector('.autocomplete-suggestion.selected');\n                if (sel) sel.className = sel.className.replace('selected', '');\n                this.className += ' selected';\n            }, that.sc);\n\n            live('autocomplete-suggestion', 'mousedown', function(e){\n                if (hasClass(this, 'autocomplete-suggestion')) { // else outside click\n                    var v = this.getAttribute('data-val');\n                    that.value = v;\n                    o.onSelect(e, v, this);\n                    that.sc.style.display = 'none';\n                }\n            }, that.sc);\n\n            that.blurHandler = function(){\n                try { var over_sb = document.querySelector('.autocomplete-suggestions:hover'); } catch(e){ var over_sb = 0; }\n                if (!over_sb) {\n                    that.last_val = that.value;\n                    that.sc.style.display = 'none';\n                    setTimeout(function(){ that.sc.style.display = 'none'; }, 350); // hide suggestions on fast input\n                } else if (that !== document.activeElement) setTimeout(function(){ that.focus(); }, 20);\n            };\n            addEvent(that, 'blur', that.blurHandler);\n\n            var suggest = function(data){\n                var val = that.value;\n                that.cache[val] = data;\n                if (data.length && val.length >= o.minChars) {\n                    var s = '';\n                    for (var i=0;i<data.length;i++) s += o.renderItem(data[i], val);\n                    that.sc.innerHTML = s;\n                    that.updateSC(0);\n                }\n                else\n                    that.sc.style.display = 'none';\n            }\n\n            that.keydownHandler = function(e){\n                var key = window.event ? e.keyCode : e.which;\n                // down (40), up (38)\n                if ((key == 40 || key == 38) && that.sc.innerHTML) {\n                    var next, sel = that.sc.querySelector('.autocomplete-suggestion.selected');\n                    if (!sel) {\n                        next = (key == 40) ? that.sc.querySelector('.autocomplete-suggestion') : that.sc.childNodes[that.sc.childNodes.length - 1]; // first : last\n                        next.className += ' selected';\n                        console.log(next);\n                        that.value = next.getAttribute('data-val');\n                    } else {\n                        next = (key == 40) ? sel.nextSibling : sel.previousSibling;\n                        if (next) {\n                            sel.className = sel.className.replace('selected', '');\n                            next.className += ' selected';\n                            that.value = next.getAttribute('data-val');\n                        }\n                        else { sel.className = sel.className.replace('selected', ''); that.value = that.last_val; next = 0; }\n                    }\n                    that.updateSC(0, next);\n                    return false;\n                }\n                // esc\n                else if (key == 27) { that.value = that.last_val; that.sc.style.display = 'none'; }\n                // enter\n                else if (key == 13 || key == 9) {\n                    var sel = that.sc.querySelector('.autocomplete-suggestion.selected');\n                    if (sel && that.sc.style.display != 'none') { o.onSelect(e, sel.getAttribute('data-val'), sel); setTimeout(function(){ that.sc.style.display = 'none'; }, 20); }\n                }\n            };\n            addEvent(that, 'keydown', that.keydownHandler);\n\n            that.keyupHandler = function(e){\n                var key = window.event ? e.keyCode : e.which;\n                if (!key || (key < 35 || key > 40) && key != 13 && key != 27) {\n                    var val = that.value;\n                    if (val.length >= o.minChars) {\n                        if (val != that.last_val) {\n                            that.last_val = val;\n                            clearTimeout(that.timer);\n                            if (o.cache) {\n                                if (val in that.cache) { suggest(that.cache[val]); return; }\n                                // no requests if previous suggestions were empty\n                                for (var i=1; i<val.length-o.minChars; i++) {\n                                    var part = val.slice(0, val.length-i);\n                                    if (part in that.cache && !that.cache[part].length) { suggest([]); return; }\n                                }\n                            }\n                            that.timer = setTimeout(function(){ o.source(val, suggest) }, o.delay);\n                        }\n                    } else {\n                        that.last_val = val;\n                        that.sc.style.display = 'none';\n                    }\n                }\n            };\n            addEvent(that, 'keyup', that.keyupHandler);\n\n            that.focusHandler = function(e){\n                that.last_val = '\\n';\n                that.keyupHandler(e)\n            };\n            if (!o.minChars) addEvent(that, 'focus', that.focusHandler);\n        }\n\n        // public destroy method\n        this.destroy = function(){\n            for (var i=0; i<elems.length; i++) {\n                var that = elems[i];\n                removeEvent(window, 'resize', that.updateSC);\n                removeEvent(that, 'blur', that.blurHandler);\n                removeEvent(that, 'focus', that.focusHandler);\n                removeEvent(that, 'keydown', that.keydownHandler);\n                removeEvent(that, 'keyup', that.keyupHandler);\n                if (that.autocompleteAttr)\n                    that.setAttribute('autocomplete', that.autocompleteAttr);\n                else\n                    that.removeAttribute('autocomplete');\n                document.body.removeChild(that.sc);\n                that = null;\n            }\n        };\n    }\n    return autoComplete;\n})();\n\n(function(){\n    if (typeof define === 'function' && define.amd)\n        define('autoComplete', function () { return autoComplete; });\n    else if (typeof module !== 'undefined' && module.exports)\n        module.exports = autoComplete;\n    else\n        window.autoComplete = autoComplete;\n})();\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/js/highlight.pack.js",
    "content": "/*! highlight.js v9.2.0 | BSD3 License | git.io/hljslicense */\n!function(e){var n=\"object\"==typeof window&&window||\"object\"==typeof self&&self;\"undefined\"!=typeof exports?e(exports):n&&(n.hljs=e({}),\"function\"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/&/gm,\"&amp;\").replace(/</gm,\"&lt;\").replace(/>/gm,\"&gt;\")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}function a(e){return/^(no-?highlight|plain|text)$/i.test(e)}function i(e){var n,t,r,i=e.className+\" \";if(i+=e.parentNode?e.parentNode.className:\"\",t=/\\blang(?:uage)?-([\\w-]+)\\b/i.exec(i))return w(t[1])?t[1]:\"no-highlight\";for(i=i.split(/\\s+/),n=0,r=i.length;r>n;n++)if(w(i[n])||a(i[n]))return i[n]}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?a+=i.nodeValue.length:1==i.nodeType&&(n.push({event:\"start\",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:\"stop\",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset<r[0].offset?e:r:\"start\"==r[0].event?e:r:e.length?e:r}function o(e){function r(e){return\" \"+e.nodeName+'=\"'+n(e.value)+'\"'}f+=\"<\"+t(e)+Array.prototype.map.call(e.attributes,r).join(\"\")+\">\"}function u(e){f+=\"</\"+t(e)+\">\"}function c(e){(\"start\"==e.event?o:u)(e.node)}for(var s=0,f=\"\",l=[];e.length||r.length;){var g=i();if(f+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g==e){l.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g==e&&g.length&&g[0].offset==s);l.reverse().forEach(o)}else\"start\"==g[0].event?l.push(g[0].node):l.pop(),c(g.splice(0,1)[0])}return f+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),\"m\"+(e.cI?\"i\":\"\")+(r?\"g\":\"\"))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(\" \").forEach(function(e){var t=e.split(\"|\");u[t[0]]=[n,t[1]?Number(t[1]):1]})};\"string\"==typeof a.k?c(\"keyword\",a.k):Object.keys(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\\b\\w+\\b/,!0),i&&(a.bK&&(a.b=\"\\\\b(\"+a.bK.split(\" \").join(\"|\")+\")\\\\b\"),a.b||(a.b=/\\B|\\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\\B|\\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||\"\",a.eW&&i.tE&&(a.tE+=(a.e?\"|\":\"\")+i.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push(\"self\"==e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var f=a.c.map(function(e){return e.bK?\"\\\\.?(\"+e.b+\")\\\\.?\":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=f.length?t(f.join(\"|\"),!0):{exec:function(){return null}}}}r(e)}function f(e,t,a,i){function o(e,n){for(var t=0;t<n.c.length;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function g(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function p(e,n,t,r){var a=r?\"\":E.classPrefix,i='<span class=\"'+a,o=t?\"\":\"</span>\";return i+=e+'\">',i+n+o}function h(){if(!k.k)return n(M);var e=\"\",t=0;k.lR.lastIndex=0;for(var r=k.lR.exec(M);r;){e+=n(M.substr(t,r.index-t));var a=g(k,r);a?(B+=a[1],e+=p(a[0],n(r[0]))):e+=n(r[0]),t=k.lR.lastIndex,r=k.lR.exec(M)}return e+n(M.substr(t))}function d(){var e=\"string\"==typeof k.sL;if(e&&!R[k.sL])return n(M);var t=e?f(k.sL,M,!0,y[k.sL]):l(M,k.sL.length?k.sL:void 0);return k.r>0&&(B+=t.r),e&&(y[k.sL]=t.top),p(t.language,t.value,!1,!0)}function b(){L+=void 0!==k.sL?d():h(),M=\"\"}function v(e,n){L+=e.cN?p(e.cN,\"\",!0):\"\",k=Object.create(e,{parent:{value:k}})}function m(e,n){if(M+=e,void 0===n)return b(),0;var t=o(n,k);if(t)return t.skip?M+=n:(t.eB&&(M+=n),b(),t.rB||t.eB||(M=n)),v(t,n),t.rB?0:n.length;var r=u(k,n);if(r){var a=k;a.skip?M+=n:(a.rE||a.eE||(M+=n),b(),a.eE&&(M=n));do k.cN&&(L+=\"</span>\"),k.skip||(B+=k.r),k=k.parent;while(k!=r.parent);return r.starts&&v(r.starts,\"\"),a.rE?0:n.length}if(c(n,k))throw new Error('Illegal lexeme \"'+n+'\" for mode \"'+(k.cN||\"<unnamed>\")+'\"');return M+=n,n.length||1}var N=w(e);if(!N)throw new Error('Unknown language: \"'+e+'\"');s(N);var x,k=i||N,y={},L=\"\";for(x=k;x!=N;x=x.parent)x.cN&&(L=p(x.cN,\"\",!0)+L);var M=\"\",B=0;try{for(var C,j,I=0;;){if(k.t.lastIndex=I,C=k.t.exec(t),!C)break;j=m(t.substr(I,C.index-I),C[0]),I=C.index+j}for(m(t.substr(I)),x=k;x.parent;x=x.parent)x.cN&&(L+=\"</span>\");return{r:B,value:L,language:e,top:k}}catch(O){if(-1!=O.message.indexOf(\"Illegal\"))return{r:0,value:n(t)};throw O}}function l(e,t){t=t||E.languages||Object.keys(R);var r={r:0,value:n(e)},a=r;return t.forEach(function(n){if(w(n)){var t=f(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}}),a.language&&(r.second_best=a),r}function g(e){return E.tabReplace&&(e=e.replace(/^((<[^>]+>|\\t)+)/gm,function(e,n){return n.replace(/\\t/g,E.tabReplace)})),E.useBR&&(e=e.replace(/\\n/g,\"<br>\")),e}function p(e,n,t){var r=n?x[n]:t,a=[e.trim()];return e.match(/\\bhljs\\b/)||a.push(\"hljs\"),-1===e.indexOf(r)&&a.push(r),a.join(\" \").trim()}function h(e){var n=i(e);if(!a(n)){var t;E.useBR?(t=document.createElementNS(\"http://www.w3.org/1999/xhtml\",\"div\"),t.innerHTML=e.innerHTML.replace(/\\n/g,\"\").replace(/<br[ \\/]*>/g,\"\\n\")):t=e;var r=t.textContent,o=n?f(n,r,!0):l(r),s=u(t);if(s.length){var h=document.createElementNS(\"http://www.w3.org/1999/xhtml\",\"div\");h.innerHTML=o.value,o.value=c(s,u(h),r)}o.value=g(o.value),e.innerHTML=o.value,e.className=p(e.className,n,o.language),e.result={language:o.language,re:o.r},o.second_best&&(e.second_best={language:o.second_best.language,re:o.second_best.r})}}function d(e){E=o(E,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll(\"pre code\");Array.prototype.forEach.call(e,h)}}function v(){addEventListener(\"DOMContentLoaded\",b,!1),addEventListener(\"load\",b,!1)}function m(n,t){var r=R[n]=t(e);r.aliases&&r.aliases.forEach(function(e){x[e]=n})}function N(){return Object.keys(R)}function w(e){return e=(e||\"\").toLowerCase(),R[e]||R[x[e]]}var E={classPrefix:\"hljs-\",tabReplace:null,useBR:!1,languages:void 0},R={},x={};return e.highlight=f,e.highlightAuto=l,e.fixMarkup=g,e.highlightBlock=h,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=w,e.inherit=o,e.IR=\"[a-zA-Z]\\\\w*\",e.UIR=\"[a-zA-Z_]\\\\w*\",e.NR=\"\\\\b\\\\d+(\\\\.\\\\d+)?\",e.CNR=\"(-?)(\\\\b0[xX][a-fA-F0-9]+|(\\\\b\\\\d+(\\\\.\\\\d*)?|\\\\.\\\\d+)([eE][-+]?\\\\d+)?)\",e.BNR=\"\\\\b(0b[01]+)\",e.RSR=\"!|!=|!==|%|%=|&|&&|&=|\\\\*|\\\\*=|\\\\+|\\\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\\\?|\\\\[|\\\\{|\\\\(|\\\\^|\\\\^=|\\\\||\\\\|=|\\\\|\\\\||~\",e.BE={b:\"\\\\\\\\[\\\\s\\\\S]\",r:0},e.ASM={cN:\"string\",b:\"'\",e:\"'\",i:\"\\\\n\",c:[e.BE]},e.QSM={cN:\"string\",b:'\"',e:'\"',i:\"\\\\n\",c:[e.BE]},e.PWM={b:/\\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\\b/},e.C=function(n,t,r){var a=e.inherit({cN:\"comment\",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:\"doctag\",b:\"(?:TODO|FIXME|NOTE|BUG|XXX):\",r:0}),a},e.CLCM=e.C(\"//\",\"$\"),e.CBCM=e.C(\"/\\\\*\",\"\\\\*/\"),e.HCM=e.C(\"#\",\"$\"),e.NM={cN:\"number\",b:e.NR,r:0},e.CNM={cN:\"number\",b:e.CNR,r:0},e.BNM={cN:\"number\",b:e.BNR,r:0},e.CSSNM={cN:\"number\",b:e.NR+\"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?\",r:0},e.RM={cN:\"regexp\",b:/\\//,e:/\\/[gimuy]*/,i:/\\n/,c:[e.BE,{b:/\\[/,e:/\\]/,r:0,c:[e.BE]}]},e.TM={cN:\"title\",b:e.IR,r:0},e.UTM={cN:\"title\",b:e.UIR,r:0},e.METHOD_GUARD={b:\"\\\\.\\\\s*\"+e.UIR,r:0},e});hljs.registerLanguage(\"bash\",function(e){var t={cN:\"variable\",v:[{b:/\\$[\\w\\d#@][\\w\\d_]*/},{b:/\\$\\{(.*?)}/}]},s={cN:\"string\",b:/\"/,e:/\"/,c:[e.BE,t,{cN:\"variable\",b:/\\$\\(/,e:/\\)/,c:[e.BE]}]},a={cN:\"string\",b:/'/,e:/'/};return{aliases:[\"sh\",\"zsh\"],l:/-?[a-z\\.]+/,k:{keyword:\"if then else elif fi for while in do done case esac function\",literal:\"true false\",built_in:\"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp\",_:\"-ne -eq -lt -gt -f -d -e -s -l -a\"},c:[{cN:\"meta\",b:/^#![^\\n]+sh\\s*$/,r:10},{cN:\"function\",b:/\\w[\\w\\d_]*\\s*\\(\\s*\\)\\s*\\{/,rB:!0,c:[e.inherit(e.TM,{b:/\\w[\\w\\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage(\"javascript\",function(e){return{aliases:[\"js\",\"jsx\"],k:{keyword:\"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as\",literal:\"true false null undefined NaN Infinity\",built_in:\"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise\"},c:[{cN:\"meta\",r:10,b:/^\\s*['\"]use (strict|asm)['\"]/},{cN:\"meta\",b:/^#!/,e:/$/},e.ASM,e.QSM,{cN:\"string\",b:\"`\",e:\"`\",c:[e.BE,{cN:\"subst\",b:\"\\\\$\\\\{\",e:\"\\\\}\"}]},e.CLCM,e.CBCM,{cN:\"number\",v:[{b:\"\\\\b(0[bB][01]+)\"},{b:\"\\\\b(0[oO][0-7]+)\"},{b:e.CNR}],r:0},{b:\"(\"+e.RSR+\"|\\\\b(case|return|throw)\\\\b)\\\\s*\",k:\"return throw case\",c:[e.CLCM,e.CBCM,e.RM,{b:/</,e:/(\\/\\w+|\\w+\\/)>/,sL:\"xml\",c:[{b:/<\\w+\\/>/,skip:!0},{b:/<\\w+/,e:/(\\/\\w+|\\w+\\/)>/,skip:!0,c:[\"self\"]}]}],r:0},{cN:\"function\",bK:\"function\",e:/\\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:\"params\",b:/\\(/,e:/\\)/,eB:!0,eE:!0,c:[e.CLCM,e.CBCM]}],i:/\\[|%/},{b:/\\$[(.]/},e.METHOD_GUARD,{cN:\"class\",bK:\"class\",e:/[{;=]/,eE:!0,i:/[:\"\\[\\]]/,c:[{bK:\"extends\"},e.UTM]},{bK:\"constructor\",e:/\\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage(\"python\",function(e){var r={cN:\"meta\",b:/^(>>>|\\.\\.\\.) /},b={cN:\"string\",c:[e.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[r],r:10},{b:/(u|b)?r?\"\"\"/,e:/\"\"\"/,c:[r],r:10},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)\"/,e:/\"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)\"/,e:/\"/},e.ASM,e.QSM]},a={cN:\"number\",r:0,v:[{b:e.BNR+\"[lLjJ]?\"},{b:\"\\\\b(0o[0-7]+)[lLjJ]?\"},{b:e.CNR+\"[lLjJ]?\"}]},l={cN:\"params\",b:/\\(/,e:/\\)/,c:[\"self\",r,a,b]};return{aliases:[\"py\",\"gyp\"],k:{keyword:\"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda async await nonlocal|10 None True False\",built_in:\"Ellipsis NotImplemented\"},i:/(<\\/|->|\\?)/,c:[r,a,b,e.HCM,{v:[{cN:\"function\",bK:\"def\",r:10},{cN:\"class\",bK:\"class\"}],e:/:/,i:/[${=;\\n,]/,c:[e.UTM,l,{b:/->/,eW:!0,k:\"None\"}]},{cN:\"meta\",b:/^[\\t ]*@/,e:/$/},{b:/\\b(print|exec)\\(/}]}});hljs.registerLanguage(\"typescript\",function(e){var r={keyword:\"in if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class public private protected get set super static implements enum export import declare type namespace abstract\",literal:\"true false null undefined NaN Infinity\",built_in:\"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document any number boolean string void\"};return{aliases:[\"ts\"],k:r,c:[{cN:\"meta\",b:/^\\s*['\"]use strict['\"]/},e.ASM,e.QSM,{cN:\"string\",b:\"`\",e:\"`\",c:[e.BE,{cN:\"subst\",b:\"\\\\$\\\\{\",e:\"\\\\}\"}]},e.CLCM,e.CBCM,{cN:\"number\",v:[{b:\"\\\\b(0[bB][01]+)\"},{b:\"\\\\b(0[oO][0-7]+)\"},{b:e.CNR}],r:0},{b:\"(\"+e.RSR+\"|\\\\b(case|return|throw)\\\\b)\\\\s*\",k:\"return throw case\",c:[e.CLCM,e.CBCM,e.RM],r:0},{cN:\"function\",b:\"function\",e:/[\\{;]/,eE:!0,k:r,c:[\"self\",e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:\"params\",b:/\\(/,e:/\\)/,eB:!0,eE:!0,k:r,c:[e.CLCM,e.CBCM],i:/[\"'\\(]/}],i:/\\[|%/,r:0},{bK:\"constructor\",e:/\\{/,eE:!0},{bK:\"module\",e:/\\{/,eE:!0},{bK:\"interface\",e:/\\{/,eE:!0,k:\"interface extends\"},{b:/\\$[(.]/},{b:\"\\\\.\"+e.IR,r:0}]}});hljs.registerLanguage(\"yaml\",function(e){var a={literal:\"{ } true false yes no Yes No True False null\"},b=\"^[ \\\\-]*\",r=\"[a-zA-Z_][\\\\w\\\\-]*\",t={cN:\"attr\",v:[{b:b+r+\":\"},{b:b+'\"'+r+'\":'},{b:b+\"'\"+r+\"':\"}]},c={cN:\"template-variable\",v:[{b:\"{{\",e:\"}}\"},{b:\"%{\",e:\"}\"}]},l={cN:\"string\",r:0,v:[{b:/'/,e:/'/},{b:/\"/,e:/\"/}],c:[e.BE,c]};return{cI:!0,aliases:[\"yml\",\"YAML\",\"yaml\"],c:[t,{cN:\"meta\",b:\"^---s*$\",r:10},{cN:\"string\",b:\"[\\\\|>] *$\",rE:!0,c:l.c,e:t.v[0].b},{b:\"<%[%=-]?\",e:\"[%-]?%>\",sL:\"ruby\",eB:!0,eE:!0,r:0},{cN:\"type\",b:\"!!\"+e.UIR},{cN:\"meta\",b:\"&\"+e.UIR+\"$\"},{cN:\"meta\",b:\"\\\\*\"+e.UIR+\"$\"},{cN:\"bullet\",b:\"^ *-\",r:0},l,e.HCM,e.CNM],k:a}});hljs.registerLanguage(\"lua\",function(e){var t=\"\\\\[=*\\\\[\",a=\"\\\\]=*\\\\]\",r={b:t,e:a,c:[\"self\"]},n=[e.C(\"--(?!\"+t+\")\",\"$\"),e.C(\"--\"+t,a,{c:[r],r:10})];return{l:e.UIR,k:{keyword:\"and break do else elseif end false for if in local nil not or repeat return then true until while\",built_in:\"_G _VERSION assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall coroutine debug io math os package string table\"},c:n.concat([{cN:\"function\",bK:\"function\",e:\"\\\\)\",c:[e.inherit(e.TM,{b:\"([_a-zA-Z]\\\\w*\\\\.)*([_a-zA-Z]\\\\w*:)?[_a-zA-Z]\\\\w*\"}),{cN:\"params\",b:\"\\\\(\",eW:!0,c:n}].concat(n)},e.CNM,e.ASM,e.QSM,{cN:\"string\",b:t,e:a,c:[r],r:5}])}});hljs.registerLanguage(\"puppet\",function(e){var s={keyword:\"and case default else elsif false if in import enherits node or true undef unless main settings $string \",literal:\"alias audit before loglevel noop require subscribe tag owner ensure group mode name|0 changes context force incl lens load_path onlyif provider returns root show_diff type_check en_address ip_address realname command environment hour monute month monthday special target weekday creates cwd ogoutput refresh refreshonly tries try_sleep umask backup checksum content ctime force ignore links mtime purge recurse recurselimit replace selinux_ignore_defaults selrange selrole seltype seluser source souirce_permissions sourceselect validate_cmd validate_replacement allowdupe attribute_membership auth_membership forcelocal gid ia_load_module members system host_aliases ip allowed_trunk_vlans description device_url duplex encapsulation etherchannel native_vlan speed principals allow_root auth_class auth_type authenticate_user k_of_n mechanisms rule session_owner shared options device fstype enable hasrestart directory present absent link atboot blockdevice device dump pass remounts poller_tag use message withpath adminfile allow_virtual allowcdrom category configfiles flavor install_options instance package_settings platform responsefile status uninstall_options vendor unless_system_user unless_uid binary control flags hasstatus manifest pattern restart running start stop allowdupe auths expiry gid groups home iterations key_membership keys managehome membership password password_max_age password_min_age profile_membership profiles project purge_ssh_keys role_membership roles salt shell uid baseurl cost descr enabled enablegroups exclude failovermethod gpgcheck gpgkey http_caching include includepkgs keepalive metadata_expire metalink mirrorlist priority protect proxy proxy_password proxy_username repo_gpgcheck s3_enabled skip_if_unavailable sslcacert sslclientcert sslclientkey sslverify mounted\",built_in:\"architecture augeasversion blockdevices boardmanufacturer boardproductname boardserialnumber cfkey dhcp_servers domain ec2_ ec2_userdata facterversion filesystems ldom fqdn gid hardwareisa hardwaremodel hostname id|0 interfaces ipaddress ipaddress_ ipaddress6 ipaddress6_ iphostnumber is_virtual kernel kernelmajversion kernelrelease kernelversion kernelrelease kernelversion lsbdistcodename lsbdistdescription lsbdistid lsbdistrelease lsbmajdistrelease lsbminordistrelease lsbrelease macaddress macaddress_ macosx_buildversion macosx_productname macosx_productversion macosx_productverson_major macosx_productversion_minor manufacturer memoryfree memorysize netmask metmask_ network_ operatingsystem operatingsystemmajrelease operatingsystemrelease osfamily partitions path physicalprocessorcount processor processorcount productname ps puppetversion rubysitedir rubyversion selinux selinux_config_mode selinux_config_policy selinux_current_mode selinux_current_mode selinux_enforced selinux_policyversion serialnumber sp_ sshdsakey sshecdsakey sshrsakey swapencrypted swapfree swapsize timezone type uniqueid uptime uptime_days uptime_hours uptime_seconds uuid virtual vlans xendomains zfs_version zonenae zones zpool_version\"},r=e.C(\"#\",\"$\"),a=\"([A-Za-z_]|::)(\\\\w|::)*\",i=e.inherit(e.TM,{b:a}),o={cN:\"variable\",b:\"\\\\$\"+a},t={cN:\"string\",c:[e.BE,o],v:[{b:/'/,e:/'/},{b:/\"/,e:/\"/}]};return{aliases:[\"pp\"],c:[r,o,t,{bK:\"class\",e:\"\\\\{|;\",i:/=/,c:[i,r]},{bK:\"define\",e:/\\{/,c:[{cN:\"section\",b:e.IR,endsParent:!0}]},{b:e.IR+\"\\\\s+\\\\{\",rB:!0,e:/\\S/,c:[{cN:\"keyword\",b:e.IR},{b:/\\{/,e:/\\}/,k:s,r:0,c:[t,r,{b:\"[a-zA-Z_]+\\\\s*=>\",rB:!0,e:\"=>\",c:[{cN:\"attr\",b:e.IR}]},{cN:\"number\",b:\"(\\\\b0[0-7_]+)|(\\\\b0x[0-9a-fA-F_]+)|(\\\\b[1-9][0-9_]*(\\\\.[0-9_]+)?)|[0_]\\\\b\",r:0},o]}],r:0}]}});hljs.registerLanguage(\"dts\",function(e){var a={cN:\"string\",v:[e.inherit(e.QSM,{b:'((u8?|U)|L)?\"'}),{b:'(u8?|U)?R\"',e:'\"',c:[e.BE]},{b:\"'\\\\\\\\?.\",e:\"'\",i:\".\"}]},c={cN:\"number\",v:[{b:\"\\\\b(\\\\d+(\\\\.\\\\d*)?|\\\\.\\\\d+)(u|U|l|L|ul|UL|f|F)\"},{b:e.CNR}],r:0},b={cN:\"meta\",b:\"#\",e:\"$\",k:{\"meta-keyword\":\"if else elif endif define undef ifdef ifndef\"},c:[{b:/\\\\\\n/,r:0},{bK:\"include\",e:\"$\",k:{\"meta-keyword\":\"include\"},c:[e.inherit(a,{cN:\"meta-string\"}),{cN:\"meta-string\",b:\"<\",e:\">\",i:\"\\\\n\"}]},a,e.CLCM,e.CBCM]},i={cN:\"variable\",b:\"\\\\&[a-z\\\\d_]*\\\\b\"},r={cN:\"meta-keyword\",b:\"/[a-z][a-z\\\\d-]*/\"},d={cN:\"symbol\",b:\"^\\\\s*[a-zA-Z_][a-zA-Z\\\\d_]*:\"},n={cN:\"params\",b:\"<\",e:\">\",c:[c,i]},s={cN:\"class\",b:/[a-zA-Z_][a-zA-Z\\d_@]*\\s{/,e:/[{;=]/,rB:!0,eE:!0},t={cN:\"class\",b:\"/\\\\s*{\",e:\"};\",r:10,c:[i,r,d,s,n,e.CLCM,e.CBCM,c,a]};return{k:\"\",c:[t,i,r,d,s,n,e.CLCM,e.CBCM,c,a,b,{b:e.IR+\"::\",k:\"\"}]}});hljs.registerLanguage(\"php\",function(e){var c={b:\"\\\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*\"},a={cN:\"meta\",b:/<\\?(php)?|\\?>/},i={cN:\"string\",c:[e.BE,a],v:[{b:'b\"',e:'\"'},{b:\"b'\",e:\"'\"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},t={v:[e.BNM,e.CNM]};return{aliases:[\"php3\",\"php4\",\"php5\",\"php6\"],cI:!0,k:\"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally\",c:[e.HCM,e.C(\"//\",\"$\",{c:[a]}),e.C(\"/\\\\*\",\"\\\\*/\",{c:[{cN:\"doctag\",b:\"@[A-Za-z]+\"}]}),e.C(\"__halt_compiler.+?;\",!1,{eW:!0,k:\"__halt_compiler\",l:e.UIR}),{cN:\"string\",b:/<<<['\"]?\\w+['\"]?$/,e:/^\\w+;?$/,c:[e.BE,{cN:\"subst\",v:[{b:/\\$\\w+/},{b:/\\{\\$/,e:/\\}/}]}]},a,c,{b:/(::|->)+[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*/},{cN:\"function\",bK:\"function\",e:/[;{]/,eE:!0,i:\"\\\\$|\\\\[|%\",c:[e.UTM,{cN:\"params\",b:\"\\\\(\",e:\"\\\\)\",c:[\"self\",c,e.CBCM,i,t]}]},{cN:\"class\",bK:\"class interface\",e:\"{\",eE:!0,i:/[:\\(\\$\"]/,c:[{bK:\"extends implements\"},e.UTM]},{bK:\"namespace\",e:\";\",i:/[\\.']/,c:[e.UTM]},{bK:\"use\",e:\";\",c:[e.UTM]},{b:\"=>\"},i,t]}});hljs.registerLanguage(\"coffeescript\",function(e){var c={keyword:\"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super then unless until loop of by when and or is isnt not\",literal:\"true false null undefined yes no on off\",built_in:\"npm require console print module global window document\"},n=\"[A-Za-z$_][0-9A-Za-z$_]*\",r={cN:\"subst\",b:/#\\{/,e:/}/,k:c},s=[e.BNM,e.inherit(e.CNM,{starts:{e:\"(\\\\s*/)?\",r:0}}),{cN:\"string\",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/\"\"\"/,e:/\"\"\"/,c:[e.BE,r]},{b:/\"/,e:/\"/,c:[e.BE,r]}]},{cN:\"regexp\",v:[{b:\"///\",e:\"///\",c:[r,e.HCM]},{b:\"//[gim]*\",r:0},{b:/\\/(?![ *])(\\\\\\/|.)*?\\/[gim]*(?=\\W|$)/}]},{b:\"@\"+n},{b:\"`\",e:\"`\",eB:!0,eE:!0,sL:\"javascript\"}];r.c=s;var i=e.inherit(e.TM,{b:n}),t=\"(\\\\(.*\\\\))?\\\\s*\\\\B[-=]>\",o={cN:\"params\",b:\"\\\\([^\\\\(]\",rB:!0,c:[{b:/\\(/,e:/\\)/,k:c,c:[\"self\"].concat(s)}]};return{aliases:[\"coffee\",\"cson\",\"iced\"],k:c,i:/\\/\\*/,c:s.concat([e.C(\"###\",\"###\"),e.HCM,{cN:\"function\",b:\"^\\\\s*\"+n+\"\\\\s*=\\\\s*\"+t,e:\"[-=]>\",rB:!0,c:[i,o]},{b:/[:\\(,=]\\s*/,r:0,c:[{cN:\"function\",b:t,e:\"[-=]>\",rB:!0,c:[o]}]},{cN:\"class\",bK:\"class\",e:\"$\",i:/[:=\"\\[\\]]/,c:[{bK:\"extends\",eW:!0,i:/[:=\"\\[\\]]/,c:[i]},i]},{b:n+\":\",e:\":\",rB:!0,rE:!0,r:0}])}});hljs.registerLanguage(\"java\",function(e){var a=e.UIR+\"(<\"+e.UIR+\"(\\\\s*,\\\\s*\"+e.UIR+\")*>)?\",t=\"false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private\",r=\"\\\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\\\d]+[\\\\d_]+[\\\\d]+|[\\\\d]+)(\\\\.([\\\\d]+[\\\\d_]+[\\\\d]+|[\\\\d]+))?|\\\\.([\\\\d]+[\\\\d_]+[\\\\d]+|[\\\\d]+))([eE][-+]?\\\\d+)?)[lLfF]?\",c={cN:\"number\",b:r,r:0};return{aliases:[\"jsp\"],k:t,i:/<\\/|#/,c:[e.C(\"/\\\\*\\\\*\",\"\\\\*/\",{r:0,c:[{b:/\\w+@/,r:0},{cN:\"doctag\",b:\"@[A-Za-z]+\"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:\"class\",bK:\"class interface\",e:/[{;=]/,eE:!0,k:\"class interface\",i:/[:\"\\[\\]]/,c:[{bK:\"extends implements\"},e.UTM]},{bK:\"new throw return else\",r:0},{cN:\"function\",b:\"(\"+a+\"\\\\s+)+\"+e.UIR+\"\\\\s*\\\\(\",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.UIR+\"\\\\s*\\\\(\",rB:!0,r:0,c:[e.UTM]},{cN:\"params\",b:/\\(/,e:/\\)/,k:t,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},c,{cN:\"meta\",b:\"@[A-Za-z]+\"}]}});hljs.registerLanguage(\"cpp\",function(t){var e={cN:\"keyword\",b:\"\\\\b[a-z\\\\d_]*_t\\\\b\"},r={cN:\"string\",v:[t.inherit(t.QSM,{b:'((u8?|U)|L)?\"'}),{b:'(u8?|U)?R\"',e:'\"',c:[t.BE]},{b:\"'\\\\\\\\?.\",e:\"'\",i:\".\"}]},i={cN:\"number\",v:[{b:\"\\\\b(\\\\d+(\\\\.\\\\d*)?|\\\\.\\\\d+)(u|U|l|L|ul|UL|f|F)\"},{b:t.CNR}],r:0},s={cN:\"meta\",b:\"#\",e:\"$\",k:{\"meta-keyword\":\"if else elif endif define undef warning error line pragma ifdef ifndef\"},c:[{b:/\\\\\\n/,r:0},{bK:\"include\",e:\"$\",k:{\"meta-keyword\":\"include\"},c:[t.inherit(r,{cN:\"meta-string\"}),{cN:\"meta-string\",b:\"<\",e:\">\",i:\"\\\\n\"}]},r,t.CLCM,t.CBCM]},a=t.IR+\"\\\\s*\\\\(\",c={keyword:\"int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignof constexpr decltype noexcept static_assert thread_local restrict _Bool complex _Complex _Imaginary atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong\",built_in:\"std string cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr\",literal:\"true false nullptr NULL\"};return{aliases:[\"c\",\"cc\",\"h\",\"c++\",\"h++\",\"hpp\"],k:c,i:\"</\",c:[e,t.CLCM,t.CBCM,i,r,s,{b:\"\\\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\\\s*<\",e:\">\",k:c,c:[\"self\",e]},{b:t.IR+\"::\",k:c},{bK:\"new throw return else\",r:0},{cN:\"function\",b:\"(\"+t.IR+\"[\\\\*&\\\\s]+)+\"+a,rB:!0,e:/[{;=]/,eE:!0,k:c,i:/[^\\w\\s\\*&]/,c:[{b:a,rB:!0,c:[t.TM],r:0},{cN:\"params\",b:/\\(/,e:/\\)/,k:c,r:0,c:[t.CLCM,t.CBCM,r,i]},t.CLCM,t.CBCM,s]}]}});hljs.registerLanguage(\"perl\",function(e){var t=\"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when\",r={cN:\"subst\",b:\"[$@]\\\\{\",e:\"\\\\}\",k:t},s={b:\"->{\",e:\"}\"},n={v:[{b:/\\$\\d/},{b:/[\\$%@](\\^\\w\\b|#\\w+(::\\w+)*|{\\w+}|\\w+(::\\w*)*)/},{b:/[\\$%@][^\\s\\w{]/,r:0}]},i=[e.BE,r,n],o=[n,e.HCM,e.C(\"^\\\\=\\\\w\",\"\\\\=cut\",{eW:!0}),s,{cN:\"string\",c:i,v:[{b:\"q[qwxr]?\\\\s*\\\\(\",e:\"\\\\)\",r:5},{b:\"q[qwxr]?\\\\s*\\\\[\",e:\"\\\\]\",r:5},{b:\"q[qwxr]?\\\\s*\\\\{\",e:\"\\\\}\",r:5},{b:\"q[qwxr]?\\\\s*\\\\|\",e:\"\\\\|\",r:5},{b:\"q[qwxr]?\\\\s*\\\\<\",e:\"\\\\>\",r:5},{b:\"qw\\\\s+q\",e:\"q\",r:5},{b:\"'\",e:\"'\",c:[e.BE]},{b:'\"',e:'\"'},{b:\"`\",e:\"`\",c:[e.BE]},{b:\"{\\\\w+}\",c:[],r:0},{b:\"-?\\\\w+\\\\s*\\\\=\\\\>\",c:[],r:0}]},{cN:\"number\",b:\"(\\\\b0[0-7_]+)|(\\\\b0x[0-9a-fA-F_]+)|(\\\\b[1-9][0-9_]*(\\\\.[0-9_]+)?)|[0_]\\\\b\",r:0},{b:\"(\\\\/\\\\/|\"+e.RSR+\"|\\\\b(split|return|print|reverse|grep)\\\\b)\\\\s*\",k:\"split return print reverse grep\",r:0,c:[e.HCM,{cN:\"regexp\",b:\"(s|tr|y)/(\\\\\\\\.|[^/])*/(\\\\\\\\.|[^/])*/[a-z]*\",r:10},{cN:\"regexp\",b:\"(m|qr)?/\",e:\"/[a-z]*\",c:[e.BE],r:0}]},{cN:\"function\",bK:\"sub\",e:\"(\\\\s*\\\\(.*?\\\\))?[;{]\",eE:!0,r:5,c:[e.TM]},{b:\"-\\\\w\\\\b\",r:0},{b:\"^__DATA__$\",e:\"^__END__$\",sL:\"mojolicious\",c:[{b:\"^@@.*\",e:\"$\",cN:\"comment\"}]}];return r.c=o,s.c=o,{aliases:[\"pl\"],k:t,c:o}});hljs.registerLanguage(\"css\",function(e){var c=\"[a-zA-Z-][a-zA-Z0-9_-]*\",t={b:/[A-Z\\_\\.\\-]+\\s*:/,rB:!0,e:\";\",eW:!0,c:[{cN:\"attribute\",b:/\\S/,e:\":\",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\\w-]+\\(/,rB:!0,c:[{cN:\"built_in\",b:/[\\w-]+/},{b:/\\(/,e:/\\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:\"number\",b:\"#[0-9A-Fa-f]+\"},{cN:\"meta\",b:\"!important\"}]}}]};return{cI:!0,i:/[=\\/|'\\$]/,c:[e.CBCM,{cN:\"selector-id\",b:/#[A-Za-z0-9_-]+/},{cN:\"selector-class\",b:/\\.[A-Za-z0-9_-]+/},{cN:\"selector-attr\",b:/\\[/,e:/\\]/,i:\"$\"},{cN:\"selector-pseudo\",b:/:(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\"'.]+/},{b:\"@(font-face|page)\",l:\"[a-z-]+\",k:\"font-face page\"},{b:\"@\",e:\"[{;]\",c:[{cN:\"keyword\",b:/\\S+/},{b:/\\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:\"selector-tag\",b:c,r:0},{b:\"{\",e:\"}\",i:/\\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage(\"dockerfile\",function(e){return{aliases:[\"docker\"],cI:!0,k:\"from maintainer cmd expose add copy entrypoint volume user workdir onbuild run env label\",c:[e.HCM,{k:\"run cmd entrypoint volume add copy workdir onbuild label\",b:/^ *(onbuild +)?(run|cmd|entrypoint|volume|add|copy|workdir|label) +/,starts:{e:/[^\\\\]\\n/,sL:\"bash\"}},{k:\"from maintainer expose env user onbuild\",b:/^ *(onbuild +)?(from|maintainer|expose|env|user|onbuild) +/,e:/[^\\\\]\\n/,c:[e.ASM,e.QSM,e.NM,e.HCM]}]}});hljs.registerLanguage(\"diff\",function(e){return{aliases:[\"patch\"],c:[{cN:\"meta\",r:10,v:[{b:/^@@ +\\-\\d+,\\d+ +\\+\\d+,\\d+ +@@$/},{b:/^\\*\\*\\* +\\d+,\\d+ +\\*\\*\\*\\*$/},{b:/^\\-\\-\\- +\\d+,\\d+ +\\-\\-\\-\\-$/}]},{cN:\"comment\",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\\-\\-\\-/,e:/$/},{b:/^\\*{3} /,e:/$/},{b:/^\\+\\+\\+/,e:/$/},{b:/\\*{5}/,e:/\\*{5}$/}]},{cN:\"addition\",b:\"^\\\\+\",e:\"$\"},{cN:\"deletion\",b:\"^\\\\-\",e:\"$\"},{cN:\"addition\",b:\"^\\\\!\",e:\"$\"}]}});hljs.registerLanguage(\"makefile\",function(e){var a={cN:\"variable\",b:/\\$\\(/,e:/\\)/,c:[e.BE]};return{aliases:[\"mk\",\"mak\"],c:[e.HCM,{b:/^\\w+\\s*\\W*=/,rB:!0,r:0,starts:{e:/\\s*\\W*=/,eE:!0,starts:{e:/$/,r:0,c:[a]}}},{cN:\"section\",b:/^[\\w]+:\\s*$/},{cN:\"meta\",b:/^\\.PHONY:/,e:/$/,k:{\"meta-keyword\":\".PHONY\"},l:/[\\.\\w]+/},{b:/^\\t+/,e:/$/,r:0,c:[e.QSM,a]}]}});hljs.registerLanguage(\"ini\",function(e){var b={cN:\"string\",c:[e.BE],v:[{b:\"'''\",e:\"'''\",r:10},{b:'\"\"\"',e:'\"\"\"',r:10},{b:'\"',e:'\"'},{b:\"'\",e:\"'\"}]};return{aliases:[\"toml\"],cI:!0,i:/\\S/,c:[e.C(\";\",\"$\"),e.HCM,{cN:\"section\",b:/^\\s*\\[+/,e:/\\]+/},{b:/^[a-z0-9\\[\\]_-]+\\s*=\\s*/,e:\"$\",rB:!0,c:[{cN:\"attr\",b:/[a-z0-9\\[\\]_-]+/},{b:/=/,eW:!0,r:0,c:[{cN:\"literal\",b:/\\bon|off|true|false|yes|no\\b/},{cN:\"variable\",v:[{b:/\\$[\\w\\d\"][\\w\\d_]*/},{b:/\\$\\{(.*?)}/}]},b,{cN:\"number\",b:/([\\+\\-]+)?[\\d]+_[\\d_]+/},e.NM]}]}]}});hljs.registerLanguage(\"apache\",function(e){var r={cN:\"number\",b:\"[\\\\$%]\\\\d+\"};return{aliases:[\"apacheconf\"],cI:!0,c:[e.HCM,{cN:\"section\",b:\"</?\",e:\">\"},{cN:\"attribute\",b:/\\w+/,r:0,k:{nomarkup:\"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername\"},starts:{e:/$/,r:0,k:{literal:\"on off all\"},c:[{cN:\"meta\",b:\"\\\\s\\\\[\",e:\"\\\\]$\"},{cN:\"variable\",b:\"[\\\\$%]\\\\{\",e:\"\\\\}\",c:[\"self\",r]},r,e.QSM]}}],i:/\\S/}});hljs.registerLanguage(\"less\",function(e){var r=\"[\\\\w-]+\",t=\"(\"+r+\"|@{\"+r+\"})\",a=[],c=[],s=function(e){return{cN:\"string\",b:\"~?\"+e+\".*?\"+e}},b=function(e,r,t){return{cN:e,b:r,r:t}},i={b:\"\\\\(\",e:\"\\\\)\",c:c,r:0};c.push(e.CLCM,e.CBCM,s(\"'\"),s('\"'),e.CSSNM,{b:\"(url|data-uri)\\\\(\",starts:{cN:\"string\",e:\"[\\\\)\\\\n]\",eE:!0}},b(\"number\",\"#[0-9A-Fa-f]+\\\\b\"),i,b(\"variable\",\"@@?\"+r,10),b(\"variable\",\"@{\"+r+\"}\"),b(\"built_in\",\"~?`[^`]*?`\"),{cN:\"attribute\",b:r+\"\\\\s*:\",e:\":\",rB:!0,eE:!0},{cN:\"meta\",b:\"!important\"});var n=c.concat({b:\"{\",e:\"}\",c:a}),o={bK:\"when\",eW:!0,c:[{bK:\"and not\"}].concat(c)},u={cN:\"attribute\",b:t,e:\":\",eE:!0,c:[e.CLCM,e.CBCM],i:/\\S/,starts:{e:\"[;}]\",rE:!0,c:c,i:\"[<=$]\"}},C={cN:\"keyword\",b:\"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\\\b\",starts:{e:\"[;{}]\",rE:!0,c:c,r:0}},l={cN:\"variable\",v:[{b:\"@\"+r+\"\\\\s*:\",r:15},{b:\"@\"+r}],starts:{e:\"[;}]\",rE:!0,c:n}},p={v:[{b:\"[\\\\.#:&\\\\[]\",e:\"[;{}]\"},{b:t+\"[^;]*{\",e:\"{\"}],rB:!0,rE:!0,i:\"[<='$\\\"]\",c:[e.CLCM,e.CBCM,o,b(\"keyword\",\"all\\\\b\"),b(\"variable\",\"@{\"+r+\"}\"),b(\"selector-tag\",t+\"%?\",0),b(\"selector-id\",\"#\"+t),b(\"selector-class\",\"\\\\.\"+t,0),b(\"selector-tag\",\"&\",0),{cN:\"selector-attr\",b:\"\\\\[\",e:\"\\\\]\"},{b:\"\\\\(\",e:\"\\\\)\",c:n},{b:\"!important\"}]};return a.push(e.CLCM,e.CBCM,C,l,p,u),{cI:!0,i:\"[=>'/<($\\\"]\",c:a}});hljs.registerLanguage(\"scala\",function(e){var t={cN:\"meta\",b:\"@[A-Za-z]+\"},a={cN:\"subst\",v:[{b:\"\\\\$[A-Za-z0-9_]+\"},{b:\"\\\\${\",e:\"}\"}]},r={cN:\"string\",v:[{b:'\"',e:'\"',i:\"\\\\n\",c:[e.BE]},{b:'\"\"\"',e:'\"\"\"',r:10},{b:'[a-z]+\"',e:'\"',i:\"\\\\n\",c:[e.BE,a]},{cN:\"string\",b:'[a-z]+\"\"\"',e:'\"\"\"',c:[a],r:10}]},c={cN:\"symbol\",b:\"'\\\\w[\\\\w\\\\d_]*(?!')\"},i={cN:\"type\",b:\"\\\\b[A-Z][A-Za-z0-9_]*\",r:0},s={cN:\"title\",b:/[^0-9\\n\\t \"'(),.`{}\\[\\]:;][^\\n\\t \"'(),.`{}\\[\\]:;]+|[^0-9\\n\\t \"'(),.`{}\\[\\]:;=]/,r:0},n={cN:\"class\",bK:\"class object trait type\",e:/[:={\\[\\n;]/,eE:!0,c:[{bK:\"extends with\",r:10},{b:/\\[/,e:/\\]/,eB:!0,eE:!0,r:0,c:[i]},{cN:\"params\",b:/\\(/,e:/\\)/,eB:!0,eE:!0,r:0,c:[i]},s]},l={cN:\"function\",bK:\"def\",e:/[:={\\[(\\n;]/,eE:!0,c:[s]};return{k:{literal:\"true false null\",keyword:\"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit\"},c:[e.CLCM,e.CBCM,r,c,i,l,n,e.CNM,t]}});hljs.registerLanguage(\"markdown\",function(e){return{aliases:[\"md\",\"mkdown\",\"mkd\"],c:[{cN:\"section\",v:[{b:\"^#{1,6}\",e:\"$\"},{b:\"^.+?\\\\n[=-]{2,}$\"}]},{b:\"<\",e:\">\",sL:\"xml\",r:0},{cN:\"bullet\",b:\"^([*+-]|(\\\\d+\\\\.))\\\\s+\"},{cN:\"strong\",b:\"[*_]{2}.+?[*_]{2}\"},{cN:\"emphasis\",v:[{b:\"\\\\*.+?\\\\*\"},{b:\"_.+?_\",r:0}]},{cN:\"quote\",b:\"^>\\\\s+\",e:\"$\"},{cN:\"code\",v:[{b:\"`.+?`\"},{b:\"^( {4}|\t)\",e:\"$\",r:0}]},{b:\"^[-\\\\*]{3,}\",e:\"$\"},{b:\"\\\\[.+?\\\\][\\\\(\\\\[].*?[\\\\)\\\\]]\",rB:!0,c:[{cN:\"string\",b:\"\\\\[\",e:\"\\\\]\",eB:!0,rE:!0,r:0},{cN:\"link\",b:\"\\\\]\\\\(\",e:\"\\\\)\",eB:!0,eE:!0},{cN:\"symbol\",b:\"\\\\]\\\\[\",e:\"\\\\]\",eB:!0,eE:!0}],r:10},{b:\"^\\\\[.+\\\\]:\",rB:!0,c:[{cN:\"symbol\",b:\"\\\\[\",e:\"\\\\]:\",eB:!0,eE:!0,starts:{cN:\"link\",e:\"$\"}}]}]}});hljs.registerLanguage(\"powershell\",function(e){var t={b:\"`[\\\\s\\\\S]\",r:0},r={cN:\"variable\",v:[{b:/\\$[\\w\\d][\\w\\d_:]*/}]},o={cN:\"literal\",b:/\\$(null|true|false)\\b/},a={cN:\"string\",b:/\"/,e:/\"/,c:[t,r,{cN:\"variable\",b:/\\$[A-z]/,e:/[^A-z]/}]},i={cN:\"string\",b:/'/,e:/'/};return{aliases:[\"ps\"],l:/-?[A-z\\.\\-]+/,cI:!0,k:{keyword:\"if else foreach return function do while until elseif begin for trap data dynamicparam end break throw param continue finally in switch exit filter try process catch\",built_in:\"Add-Content Add-History Add-Member Add-PSSnapin Clear-Content Clear-Item Clear-Item Property Clear-Variable Compare-Object ConvertFrom-SecureString Convert-Path ConvertTo-Html ConvertTo-SecureString Copy-Item Copy-ItemProperty Export-Alias Export-Clixml Export-Console Export-Csv ForEach-Object Format-Custom Format-List Format-Table Format-Wide Get-Acl Get-Alias Get-AuthenticodeSignature Get-ChildItem Get-Command Get-Content Get-Credential Get-Culture Get-Date Get-EventLog Get-ExecutionPolicy Get-Help Get-History Get-Host Get-Item Get-ItemProperty Get-Location Get-Member Get-PfxCertificate Get-Process Get-PSDrive Get-PSProvider Get-PSSnapin Get-Service Get-TraceSource Get-UICulture Get-Unique Get-Variable Get-WmiObject Group-Object Import-Alias Import-Clixml Import-Csv Invoke-Expression Invoke-History Invoke-Item Join-Path Measure-Command Measure-Object Move-Item Move-ItemProperty New-Alias New-Item New-ItemProperty New-Object New-PSDrive New-Service New-TimeSpan New-Variable Out-Default Out-File Out-Host Out-Null Out-Printer Out-String Pop-Location Push-Location Read-Host Remove-Item Remove-ItemProperty Remove-PSDrive Remove-PSSnapin Remove-Variable Rename-Item Rename-ItemProperty Resolve-Path Restart-Service Resume-Service Select-Object Select-String Set-Acl Set-Alias Set-AuthenticodeSignature Set-Content Set-Date Set-ExecutionPolicy Set-Item Set-ItemProperty Set-Location Set-PSDebug Set-Service Set-TraceSource Set-Variable Sort-Object Split-Path Start-Service Start-Sleep Start-Transcript Stop-Process Stop-Service Stop-Transcript Suspend-Service Tee-Object Test-Path Trace-Command Update-FormatData Update-TypeData Where-Object Write-Debug Write-Error Write-Host Write-Output Write-Progress Write-Verbose Write-Warning\",nomarkup:\"-ne -eq -lt -gt -ge -le -not -like -notlike -match -notmatch -contains -notcontains -in -notin -replace\"},c:[e.HCM,e.NM,a,i,o,r]}});hljs.registerLanguage(\"go\",function(e){var t={keyword:\"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune\",literal:\"true false iota nil\",built_in:\"append cap close complex copy imag len make new panic print println real recover delete\"};return{aliases:[\"golang\"],k:t,i:\"</\",c:[e.CLCM,e.CBCM,e.QSM,{cN:\"string\",b:\"'\",e:\"[^\\\\\\\\]'\"},{cN:\"string\",b:\"`\",e:\"`\"},{cN:\"number\",b:e.CNR+\"[dflsi]?\",r:0},e.CNM]}});hljs.registerLanguage(\"json\",function(e){var i={literal:\"true false null\"},n=[e.QSM,e.CNM],r={e:\",\",eW:!0,eE:!0,c:n,k:i},t={b:\"{\",e:\"}\",c:[{cN:\"attr\",b:/\"/,e:/\"/,c:[e.BE],i:\"\\\\n\"},e.inherit(r,{b:/:/})],i:\"\\\\S\"},c={b:\"\\\\[\",e:\"\\\\]\",c:[e.inherit(r)],i:\"\\\\S\"};return n.splice(n.length,0,t,c),{c:n,k:i,i:\"\\\\S\"}});hljs.registerLanguage(\"xml\",function(s){var e=\"[A-Za-z0-9\\\\._:-]+\",t={eW:!0,i:/</,r:0,c:[{cN:\"attr\",b:e,r:0},{b:\"=\",r:0,c:[{cN:\"string\",v:[{b:/\"/,e:/\"/},{b:/'/,e:/'/},{b:/[^\\s\\/>]+/}]}]}]};return{aliases:[\"html\",\"xhtml\",\"rss\",\"atom\",\"xsl\",\"plist\"],cI:!0,c:[{cN:\"meta\",b:\"<!DOCTYPE\",e:\">\",r:10,c:[{b:\"\\\\[\",e:\"\\\\]\"}]},s.C(\"<!--\",\"-->\",{r:10}),{b:\"<\\\\!\\\\[CDATA\\\\[\",e:\"\\\\]\\\\]>\",r:10},{b:/<\\?(php)?/,e:/\\?>/,sL:\"php\",c:[{b:\"/\\\\*\",e:\"\\\\*/\",skip:!0}]},{cN:\"tag\",b:\"<style(?=\\\\s|>|$)\",e:\">\",k:{name:\"style\"},c:[t],starts:{e:\"</style>\",rE:!0,sL:[\"css\",\"xml\"]}},{cN:\"tag\",b:\"<script(?=\\\\s|>|$)\",e:\">\",k:{name:\"script\"},c:[t],starts:{e:\"</script>\",rE:!0,sL:[\"actionscript\",\"javascript\",\"handlebars\",\"xml\"]}},{cN:\"meta\",v:[{b:/<\\?xml/,e:/\\?>/,r:10},{b:/<\\?\\w+/,e:/\\?>/}]},{cN:\"tag\",b:\"</?\",e:\"/?>\",c:[{cN:\"name\",b:/[^\\/><\\s]+/,r:0},t]}]}});hljs.registerLanguage(\"sql\",function(e){var t=e.C(\"--\",\"$\");return{cI:!0,i:/[<>{}*]/,c:[{bK:\"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke\",e:/;/,eW:!0,k:{keyword:\"abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias allocate allow alter always analyze ancillary and any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second section securefile security seed segment select self sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek\",literal:\"true false null\",built_in:\"array bigint binary bit blob boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text varchar varying void\"},c:[{cN:\"string\",b:\"'\",e:\"'\",c:[e.BE,{b:\"''\"}]},{cN:\"string\",b:'\"',e:'\"',c:[e.BE,{b:'\"\"'}]},{cN:\"string\",b:\"`\",e:\"`\",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]}});hljs.registerLanguage(\"groovy\",function(e){return{k:{literal:\"true false null\",keyword:\"byte short char int long boolean float double void def as in assert trait super this abstract static volatile transient public private protected synchronized final class interface enum if else for while switch case break default continue throw throws try catch finally implements extends new import package return instanceof\"},c:[e.C(\"/\\\\*\\\\*\",\"\\\\*/\",{r:0,c:[{b:/\\w+@/,r:0},{cN:\"doctag\",b:\"@[A-Za-z]+\"}]}),e.CLCM,e.CBCM,{cN:\"string\",b:'\"\"\"',e:'\"\"\"'},{cN:\"string\",b:\"'''\",e:\"'''\"},{cN:\"string\",b:\"\\\\$/\",e:\"/\\\\$\",r:10},e.ASM,{cN:\"regexp\",b:/~?\\/[^\\/\\n]+\\//,c:[e.BE]},e.QSM,{cN:\"meta\",b:\"^#!/usr/bin/env\",e:\"$\",i:\"\\n\"},e.BNM,{cN:\"class\",bK:\"class interface trait enum\",e:\"{\",i:\":\",c:[{bK:\"extends implements\"},e.UTM]},e.CNM,{cN:\"meta\",b:\"@[A-Za-z]+\"},{cN:\"string\",b:/[^\\?]{0}[A-Za-z0-9_$]+ *:/},{b:/\\?/,e:/\\:/},{cN:\"symbol\",b:\"^\\\\s*[A-Za-z0-9_$]+:\",r:0}],i:/#|<\\//}});hljs.registerLanguage(\"cs\",function(e){var t=\"abstract as base bool break byte case catch char checked const continue decimal dynamic default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long null when object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while async protected public private internal ascending descending from get group into join let orderby partial select set value var where yield\",r=e.IR+\"(<\"+e.IR+\">)?\";return{aliases:[\"csharp\"],k:t,i:/::/,c:[e.C(\"///\",\"$\",{rB:!0,c:[{cN:\"doctag\",v:[{b:\"///\",r:0},{b:\"<!--|-->\"},{b:\"</?\",e:\">\"}]}]}),e.CLCM,e.CBCM,{cN:\"meta\",b:\"#\",e:\"$\",k:{\"meta-keyword\":\"if else elif endif define undef warning error line region endregion pragma checksum\"}},{cN:\"string\",b:'@\"',e:'\"',c:[{b:'\"\"'}]},e.ASM,e.QSM,e.CNM,{bK:\"class interface\",e:/[{;=]/,i:/[^\\s:]/,c:[e.TM,e.CLCM,e.CBCM]},{bK:\"namespace\",e:/[{;=]/,i:/[^\\s:]/,c:[e.inherit(e.TM,{b:\"[a-zA-Z](\\\\.?\\\\w)*\"}),e.CLCM,e.CBCM]},{bK:\"new return throw await\",r:0},{cN:\"function\",b:\"(\"+r+\"\\\\s+)+\"+e.IR+\"\\\\s*\\\\(\",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.IR+\"\\\\s*\\\\(\",rB:!0,c:[e.TM],r:0},{cN:\"params\",b:/\\(/,e:/\\)/,eB:!0,eE:!0,k:t,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]}]}});hljs.registerLanguage(\"ruby\",function(e){var b=\"[a-zA-Z_]\\\\w*[!?=]?|[-+~]\\\\@|<<|>>|=~|===?|<=>|[<>]=?|\\\\*\\\\*|[-/+%^&*~`|]|\\\\[\\\\]=?\",c=\"and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor\",r={cN:\"doctag\",b:\"@[A-Za-z]+\"},a={b:\"#<\",e:\">\"},s=[e.C(\"#\",\"$\",{c:[r]}),e.C(\"^\\\\=begin\",\"^\\\\=end\",{c:[r],r:10}),e.C(\"^__END__\",\"\\\\n$\")],n={cN:\"subst\",b:\"#\\\\{\",e:\"}\",k:c},t={cN:\"string\",c:[e.BE,n],v:[{b:/'/,e:/'/},{b:/\"/,e:/\"/},{b:/`/,e:/`/},{b:\"%[qQwWx]?\\\\(\",e:\"\\\\)\"},{b:\"%[qQwWx]?\\\\[\",e:\"\\\\]\"},{b:\"%[qQwWx]?{\",e:\"}\"},{b:\"%[qQwWx]?<\",e:\">\"},{b:\"%[qQwWx]?/\",e:\"/\"},{b:\"%[qQwWx]?%\",e:\"%\"},{b:\"%[qQwWx]?-\",e:\"-\"},{b:\"%[qQwWx]?\\\\|\",e:\"\\\\|\"},{b:/\\B\\?(\\\\\\d{1,3}|\\\\x[A-Fa-f0-9]{1,2}|\\\\u[A-Fa-f0-9]{4}|\\\\?\\S)\\b/}]},i={cN:\"params\",b:\"\\\\(\",e:\"\\\\)\",endsParent:!0,k:c},d=[t,a,{cN:\"class\",bK:\"class module\",e:\"$|;\",i:/=/,c:[e.inherit(e.TM,{b:\"[A-Za-z_]\\\\w*(::\\\\w+)*(\\\\?|\\\\!)?\"}),{b:\"<\\\\s*\",c:[{b:\"(\"+e.IR+\"::)?\"+e.IR}]}].concat(s)},{cN:\"function\",bK:\"def\",e:\"$|;\",c:[e.inherit(e.TM,{b:b}),i].concat(s)},{cN:\"symbol\",b:e.UIR+\"(\\\\!|\\\\?)?:\",r:0},{cN:\"symbol\",b:\":\",c:[t,{b:b}],r:0},{cN:\"number\",b:\"(\\\\b0[0-7_]+)|(\\\\b0x[0-9a-fA-F_]+)|(\\\\b[1-9][0-9_]*(\\\\.[0-9_]+)?)|[0_]\\\\b\",r:0},{b:\"(\\\\$\\\\W)|((\\\\$|\\\\@\\\\@?)(\\\\w+))\"},{b:\"(\"+e.RSR+\")\\\\s*\",c:[a,{cN:\"regexp\",c:[e.BE,n],i:/\\n/,v:[{b:\"/\",e:\"/[a-z]*\"},{b:\"%r{\",e:\"}[a-z]*\"},{b:\"%r\\\\(\",e:\"\\\\)[a-z]*\"},{b:\"%r!\",e:\"![a-z]*\"},{b:\"%r\\\\[\",e:\"\\\\][a-z]*\"}]}].concat(s),r:0}].concat(s);n.c=d,i.c=d;var o=\"[>?]>\",l=\"[\\\\w#]+\\\\(\\\\w+\\\\):\\\\d+:\\\\d+>\",u=\"(\\\\w+-)?\\\\d+\\\\.\\\\d+\\\\.\\\\d(p\\\\d+)?[^>]+>\",w=[{b:/^\\s*=>/,starts:{e:\"$\",c:d}},{cN:\"meta\",b:\"^(\"+o+\"|\"+l+\"|\"+u+\")\",starts:{e:\"$\",c:d}}];return{aliases:[\"rb\",\"gemspec\",\"podspec\",\"thor\",\"irb\"],k:c,i:/\\/\\*/,c:s.concat(w).concat(d)}});hljs.registerLanguage(\"http\",function(e){var t=\"HTTP/[0-9\\\\.]+\";return{aliases:[\"https\"],i:\"\\\\S\",c:[{b:\"^\"+t,e:\"$\",c:[{cN:\"number\",b:\"\\\\b\\\\d{3}\\\\b\"}]},{b:\"^[A-Z]+ (.*?) \"+t+\"$\",rB:!0,e:\"$\",c:[{cN:\"string\",b:\" \",e:\" \",eB:!0,eE:!0},{b:t},{cN:\"keyword\",b:\"[A-Z]+\"}]},{cN:\"attribute\",b:\"^\\\\w\",e:\": \",eE:!0,i:\"\\\\n|\\\\s|=\",starts:{e:\"$\",r:0}},{b:\"\\\\n\\\\n\",starts:{sL:[],eW:!0}}]}});hljs.registerLanguage(\"vbnet\",function(e){return{aliases:[\"vb\"],cI:!0,k:{keyword:\"addhandler addressof alias and andalso aggregate ansi as assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into is isfalse isnot istrue join key let lib like loop me mid mod module mustinherit mustoverride mybase myclass namespace narrowing new next not notinheritable notoverridable of off on operator option optional or order orelse overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim rem removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly xor\",built_in:\"boolean byte cbool cbyte cchar cdate cdec cdbl char cint clng cobj csbyte cshort csng cstr ctype date decimal directcast double gettype getxmlnamespace iif integer long object sbyte short single string trycast typeof uinteger ulong ushort\",literal:\"true false nothing\"},i:\"//|{|}|endif|gosub|variant|wend\",c:[e.inherit(e.QSM,{c:[{b:'\"\"'}]}),e.C(\"'\",\"$\",{rB:!0,c:[{cN:\"doctag\",b:\"'''|<!--|-->\",c:[e.PWM]},{cN:\"doctag\",b:\"</?\",e:\">\",c:[e.PWM]}]}),e.CNM,{cN:\"meta\",b:\"#\",e:\"$\",k:{\"meta-keyword\":\"if else elseif end region externalsource\"}}]}});hljs.registerLanguage(\"objectivec\",function(e){var t={cN:\"built_in\",b:\"(AV|CA|CF|CG|CI|MK|MP|NS|UI|XC)\\\\w+\"},i={keyword:\"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required\",literal:\"false true FALSE TRUE nil YES NO NULL\",built_in:\"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once\"},n=/[a-zA-Z@][a-zA-Z0-9_]*/,o=\"@interface @class @protocol @implementation\";return{aliases:[\"mm\",\"objc\",\"obj-c\"],k:i,l:n,i:\"</\",c:[t,e.CLCM,e.CBCM,e.CNM,e.QSM,{cN:\"string\",v:[{b:'@\"',e:'\"',i:\"\\\\n\",c:[e.BE]},{b:\"'\",e:\"[^\\\\\\\\]'\",i:\"[^\\\\\\\\][^']\"}]},{cN:\"meta\",b:\"#\",e:\"$\",c:[{cN:\"meta-string\",v:[{b:'\"',e:'\"'},{b:\"<\",e:\">\"}]}]},{cN:\"class\",b:\"(\"+o.split(\" \").join(\"|\")+\")\\\\b\",e:\"({|$)\",eE:!0,k:o,l:n,c:[e.UTM]},{b:\"\\\\.\"+e.UIR,r:0}]}});hljs.registerLanguage(\"nginx\",function(e){var r={cN:\"variable\",v:[{b:/\\$\\d+/},{b:/\\$\\{/,e:/}/},{b:\"[\\\\$\\\\@]\"+e.UIR}]},b={eW:!0,l:\"[a-z/_]+\",k:{literal:\"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll\"},r:0,i:\"=>\",c:[e.HCM,{cN:\"string\",c:[e.BE,r],v:[{b:/\"/,e:/\"/},{b:/'/,e:/'/}]},{b:\"([a-z]+):/\",e:\"\\\\s\",eW:!0,eE:!0,c:[r]},{cN:\"regexp\",c:[e.BE,r],v:[{b:\"\\\\s\\\\^\",e:\"\\\\s|{|;\",rE:!0},{b:\"~\\\\*?\\\\s+\",e:\"\\\\s|{|;\",rE:!0},{b:\"\\\\*(\\\\.[a-z\\\\-]+)+\"},{b:\"([a-z\\\\-]+\\\\.)+\\\\*\"}]},{cN:\"number\",b:\"\\\\b\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}\\\\.\\\\d{1,3}(:\\\\d{1,5})?\\\\b\"},{cN:\"number\",b:\"\\\\b\\\\d+[kKmMgGdshdwy]*\\\\b\",r:0},r]};return{aliases:[\"nginxconf\"],c:[e.HCM,{b:e.UIR+\"\\\\s+{\",rB:!0,e:\"{\",c:[{cN:\"section\",b:e.UIR}],r:0},{b:e.UIR+\"\\\\s\",e:\";|{\",rB:!0,c:[{cN:\"attribute\",b:e.UIR,starts:b}],r:0}],i:\"[^\\\\s\\\\}]\"}});"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/js/hugo-learn.js",
    "content": "// Get Parameters from some url\nvar getUrlParameter = function getUrlParameter(sPageURL) {\n    var url = sPageURL.split('?');\n    var obj = {};\n    if (url.length == 2) {\n      var sURLVariables = url[1].split('&'),\n          sParameterName,\n          i;\n      for (i = 0; i < sURLVariables.length; i++) {\n          sParameterName = sURLVariables[i].split('=');\n          obj[sParameterName[0]] = sParameterName[1];\n      }\n      return obj;\n    } else {\n      return undefined;\n    }\n};\n\n// Execute actions on images generated from Markdown pages\nvar images = $(\"div#body-inner img\").not(\".inline\");\n// Wrap image inside a featherlight (to get a full size view in a popup)\nimages.wrap(function(){\n  var image =$(this);\n  if (!image.parent(\"a\").length) {\n    return \"<a href='\" + image[0].src + \"' data-featherlight='image'></a>\";\n  }\n});\n\n// Change styles, depending on parameters set to the image\nimages.each(function(index){\n  var image = $(this)\n  var o = getUrlParameter(image[0].src);\n  if (typeof o !== \"undefined\") {\n    var h = o[\"height\"];\n    var w = o[\"width\"];\n    var c = o[\"classes\"];\n    image.css(\"width\", function() {\n      if (typeof w !== \"undefined\") {\n        return w;\n      } else {\n        return \"auto\";\n      }\n    });\n    image.css(\"height\", function() {\n      if (typeof h !== \"undefined\") {\n        return h;\n      } else {\n        return \"auto\";\n      }\n    });\n    if (typeof c !== \"undefined\") {\n      var classes = c.split(',');\n      for (i = 0; i < classes.length; i++) {\n        image.addClass(classes[i]);\n      }\n    }\n  }\n});\n\n// Stick the top to the top of the screen when  scrolling\n$(document).ready(function(){\n  $(\"#top-bar\").sticky({topSpacing:0, zIndex: 1000});\n});\n\n\njQuery(document).ready(function() {\n  // Add link button for every\n  var text, clip = new Clipboard('.anchor');\n  $(\"h1~h2,h1~h3,h1~h4,h1~h5,h1~h6\").append(function(index, html){\n    var element = $(this);\n    var url = document.location.origin + document.location.pathname;\n    var link = url + \"#\"+element[0].id;\n    return \" <span class='anchor' data-clipboard-text='\"+link+\"'>\" +\n      \"<i class='fa fa-link fa-lg'></i>\" +\n      \"</span>\"\n    ;\n  });\n\n  $(\".anchor\").on('mouseleave', function(e) {\n    $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w');\n  });\n\n  clip.on('success', function(e) {\n      e.clearSelection();\n      $(e.trigger).attr('aria-label', 'Link copied to clipboard!').addClass('tooltipped tooltipped-s');\n  });\n\n});\n\n\njQuery(document).ready(function(){\n\t$(\"#sidebar .topics li svg\").click(function(event){   \n\t\tevent.preventDefault();\n\t\tevent.stopPropagation();\n\t\tvar that=$(this);\n    that.toggle().siblings('svg').toggle()\n\t\tthat.closest(\"li\").children(\"ul\").slideToggle('fast',\"linear\");\n\t});\n})\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/js/jquery.sticky.js",
    "content": "// Sticky Plugin v1.0.4 for jQuery\n// =============\n// Author: Anthony Garand\n// Improvements by German M. Bravo (Kronuz) and Ruud Kamphuis (ruudk)\n// Improvements by Leonardo C. Daronco (daronco)\n// Created: 02/14/2011\n// Date: 07/20/2015\n// Website: http://stickyjs.com/\n// Description: Makes an element on the page stick on the screen as you scroll\n//              It will only set the 'top' and 'position' of your element, you\n//              might need to adjust the width in some cases.\n\n(function (factory) {\n  if (typeof define === 'function' && define.amd) {\n      // AMD. Register as an anonymous module.\n      define(['jquery'], factory);\n  } else if (typeof module === 'object' && module.exports) {\n      // Node/CommonJS\n      module.exports = factory(require('jquery'));\n  } else {\n      // Browser globals\n      factory(jQuery);\n  }\n}(function ($) {\n  var slice = Array.prototype.slice; // save ref to original slice()\n  var splice = Array.prototype.splice; // save ref to original slice()\n\nvar defaults = {\n    topSpacing: 0,\n    bottomSpacing: 0,\n    className: 'is-sticky',\n    wrapperClassName: 'sticky-wrapper',\n    center: false,\n    getWidthFrom: '',\n    widthFromWrapper: true, // works only when .getWidthFrom is empty\n    responsiveWidth: false,\n    zIndex: 'inherit'\n  },\n  $window = $(window),\n  $document = $(document),\n  $TableOfContents = $('#TableOfContents'),\n  sticked = [],\n  windowHeight = $window.height(),\n  scroller = function() {\n    var scrollTop = $window.scrollTop(),\n      documentHeight = $document.height(),\n      dwh = documentHeight - windowHeight,\n      extra = (scrollTop > dwh) ? dwh - scrollTop : 0;\n\n    for (var i = 0, l = sticked.length; i < l; i++) {\n      var s = sticked[i],\n        elementTop = s.stickyWrapper.offset().top,\n        etse = elementTop - s.topSpacing - extra;\n\n      //update height in case of dynamic content\n      s.stickyWrapper.css('height', s.stickyElement.outerHeight());\n\n      if (scrollTop <= etse) {\n        if (s.currentTop !== null) {\n          s.stickyElement\n            .css({\n              'width': '',\n              'position': '',\n              'top': '',\n              'z-index': ''\n            });\n          s.stickyElement.parent().removeClass(s.className);\n          $TableOfContents.removeClass('sticky');\n          s.stickyElement.trigger('sticky-end', [s]);\n          s.currentTop = null;\n        }\n      }\n      else {\n        var newTop = documentHeight - s.stickyElement.outerHeight()\n          - s.topSpacing - s.bottomSpacing - scrollTop - extra;\n        if (newTop < 0) {\n          newTop = newTop + s.topSpacing;\n        } else {\n          newTop = s.topSpacing;\n        }\n        if (s.currentTop !== newTop) {\n          var newWidth;\n          if (s.getWidthFrom) {\n              padding =  s.stickyElement.innerWidth() - s.stickyElement.width();\n              newWidth = $(s.getWidthFrom).width() - padding || null;\n          } else if (s.widthFromWrapper) {\n              newWidth = s.stickyWrapper.width();\n          }\n          if (newWidth == null) {\n              newWidth = s.stickyElement.width();\n          }\n          s.stickyElement\n            .css('width', newWidth)\n            .css('position', 'fixed')\n            .css('top', newTop)\n            .css('z-index', s.zIndex);\n          \n          s.stickyElement.parent().addClass(s.className);\n          $TableOfContents.addClass('sticky')\n\n          if (s.currentTop === null) {\n            s.stickyElement.trigger('sticky-start', [s]);\n          } else {\n            // sticky is started but it have to be repositioned\n            s.stickyElement.trigger('sticky-update', [s]);\n          }\n\n          if (s.currentTop === s.topSpacing && s.currentTop > newTop || s.currentTop === null && newTop < s.topSpacing) {\n            // just reached bottom || just started to stick but bottom is already reached\n            s.stickyElement.trigger('sticky-bottom-reached', [s]);\n          } else if(s.currentTop !== null && newTop === s.topSpacing && s.currentTop < newTop) {\n            // sticky is started && sticked at topSpacing && overflowing from top just finished\n            s.stickyElement.trigger('sticky-bottom-unreached', [s]);\n          }\n\n          s.currentTop = newTop;\n        }\n\n        // Check if sticky has reached end of container and stop sticking\n        var stickyWrapperContainer = s.stickyWrapper.parent();\n        var unstick = (s.stickyElement.offset().top + s.stickyElement.outerHeight() >= stickyWrapperContainer.offset().top + stickyWrapperContainer.outerHeight()) && (s.stickyElement.offset().top <= s.topSpacing);\n\n        if( unstick ) {\n          s.stickyElement\n            .css('position', 'absolute')\n            .css('top', '')\n            .css('bottom', 0)\n            .css('z-index', '');\n        } else {\n          s.stickyElement\n            .css('position', 'fixed')\n            .css('top', newTop)\n            .css('bottom', '')\n            .css('z-index', s.zIndex);\n        }\n      }\n    }\n  },\n  resizer = function() {\n    windowHeight = $window.height();\n\n    for (var i = 0, l = sticked.length; i < l; i++) {\n      var s = sticked[i];\n      var newWidth = null;\n      if (s.getWidthFrom) {\n          if (s.responsiveWidth) {\n              newWidth = $(s.getWidthFrom).width();\n          }\n      } else if(s.widthFromWrapper) {\n          newWidth = s.stickyWrapper.width();\n      }\n      if (newWidth != null) {\n          s.stickyElement.css('width', newWidth);\n      }\n    }\n  },\n  methods = {\n    init: function(options) {\n      return this.each(function() {\n        var o = $.extend({}, defaults, options);\n        var stickyElement = $(this);\n\n        var stickyId = stickyElement.attr('id');\n        var wrapperId = stickyId ? stickyId + '-' + defaults.wrapperClassName : defaults.wrapperClassName;\n        var wrapper = $('<div></div>')\n          .attr('id', wrapperId)\n          .addClass(o.wrapperClassName);\n\n        stickyElement.wrapAll(function() {\n          if ($(this).parent(\"#\" + wrapperId).length == 0) {\n                  return wrapper;\n          }\n});\n\n        var stickyWrapper = stickyElement.parent();\n\n        if (o.center) {\n          stickyWrapper.css({width:stickyElement.outerWidth(),marginLeft:\"auto\",marginRight:\"auto\"});\n        }\n\n        if (stickyElement.css(\"float\") === \"right\") {\n          stickyElement.css({\"float\":\"none\"}).parent().css({\"float\":\"right\"});\n        }\n\n        o.stickyElement = stickyElement;\n        o.stickyWrapper = stickyWrapper;\n        o.currentTop    = null;\n\n        sticked.push(o);\n\n        methods.setWrapperHeight(this);\n        methods.setupChangeListeners(this);\n      });\n    },\n\n    setWrapperHeight: function(stickyElement) {\n      var element = $(stickyElement);\n      var stickyWrapper = element.parent();\n      if (stickyWrapper) {\n        stickyWrapper.css('height', element.outerHeight());\n      }\n    },\n\n    setupChangeListeners: function(stickyElement) {\n      if (window.MutationObserver) {\n        var mutationObserver = new window.MutationObserver(function(mutations) {\n          if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) {\n            methods.setWrapperHeight(stickyElement);\n          }\n        });\n        mutationObserver.observe(stickyElement, {subtree: true, childList: true});\n      } else {\n        if (window.addEventListener) {\n          stickyElement.addEventListener('DOMNodeInserted', function() {\n            methods.setWrapperHeight(stickyElement);\n          }, false);\n          stickyElement.addEventListener('DOMNodeRemoved', function() {\n            methods.setWrapperHeight(stickyElement);\n          }, false);\n        } else if (window.attachEvent) {\n          stickyElement.attachEvent('onDOMNodeInserted', function() {\n            methods.setWrapperHeight(stickyElement);\n          });\n          stickyElement.attachEvent('onDOMNodeRemoved', function() {\n            methods.setWrapperHeight(stickyElement);\n          });\n        }\n      }\n    },\n    update: scroller,\n    unstick: function(options) {\n      return this.each(function() {\n        var that = this;\n        var unstickyElement = $(that);\n\n        var removeIdx = -1;\n        var i = sticked.length;\n        while (i-- > 0) {\n          if (sticked[i].stickyElement.get(0) === that) {\n              splice.call(sticked,i,1);\n              removeIdx = i;\n          }\n        }\n        if(removeIdx !== -1) {\n          unstickyElement.unwrap();\n          unstickyElement\n            .css({\n              'width': '',\n              'position': '',\n              'top': '',\n              'float': '',\n              'z-index': ''\n            })\n          ;\n        }\n      });\n    }\n  };\n\n// should be more efficient than using $window.scroll(scroller) and $window.resize(resizer):\nif (window.addEventListener) {\n  window.addEventListener('scroll', scroller, false);\n  window.addEventListener('resize', resizer, false);\n} else if (window.attachEvent) {\n  window.attachEvent('onscroll', scroller);\n  window.attachEvent('onresize', resizer);\n}\n\n$.fn.sticky = function(method) {\n  if (methods[method]) {\n    return methods[method].apply(this, slice.call(arguments, 1));\n  } else if (typeof method === 'object' || !method ) {\n    return methods.init.apply( this, arguments );\n  } else {\n    $.error('Method ' + method + ' does not exist on jQuery.sticky');\n  }\n};\n\n$.fn.unstick = function(method) {\n  if (methods[method]) {\n    return methods[method].apply(this, slice.call(arguments, 1));\n  } else if (typeof method === 'object' || !method ) {\n    return methods.unstick.apply( this, arguments );\n  } else {\n    $.error('Method ' + method + ' does not exist on jQuery.sticky');\n  }\n};\n$(function() {\n  setTimeout(scroller, 0);\n});\n}));\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/js/learn.js",
    "content": "// Scrollbar Width function\nfunction getScrollBarWidth() {\n    var inner = document.createElement('p');\n    inner.style.width = \"100%\";\n    inner.style.height = \"200px\";\n\n    var outer = document.createElement('div');\n    outer.style.position = \"absolute\";\n    outer.style.top = \"0px\";\n    outer.style.left = \"0px\";\n    outer.style.visibility = \"hidden\";\n    outer.style.width = \"200px\";\n    outer.style.height = \"150px\";\n    outer.style.overflow = \"hidden\";\n    outer.appendChild(inner);\n\n    document.body.appendChild(outer);\n    var w1 = inner.offsetWidth;\n    outer.style.overflow = 'scroll';\n    var w2 = inner.offsetWidth;\n    if (w1 == w2) w2 = outer.clientWidth;\n\n    document.body.removeChild(outer);\n\n    return (w1 - w2);\n};\n\nfunction setMenuHeight() {\n    $('#sidebar .leftMenu').height($(window).innerHeight() - $('#header-wrapper').height() - 240);\n    $('#sidebar .leftMenu').perfectScrollbar('update');\n}\n\nfunction fallbackMessage(action) {\n    var actionMsg = '';\n    var actionKey = (action === 'cut' ? 'X' : 'C');\n\n    if (/iPhone|iPad/i.test(navigator.userAgent)) {\n        actionMsg = 'No support :(';\n    }\n    else if (/Mac/i.test(navigator.userAgent)) {\n        actionMsg = 'Press ⌘-' + actionKey + ' to ' + action;\n    }\n    else {\n        actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action;\n    }\n\n    return actionMsg;\n}\n\n// for the window resize\n$(window).resize(function() {\n    setMenuHeight();\n});\n\n// debouncing function from John Hann\n// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/\n(function($, sr) {\n\n    var debounce = function(func, threshold, execAsap) {\n        var timeout;\n\n        return function debounced() {\n            var obj = this, args = arguments;\n\n            function delayed() {\n                if (!execAsap)\n                    func.apply(obj, args);\n                timeout = null;\n            };\n\n            if (timeout)\n                clearTimeout(timeout);\n            else if (execAsap)\n                func.apply(obj, args);\n\n            timeout = setTimeout(delayed, threshold || 100);\n        };\n    }\n    // smartresize\n    jQuery.fn[sr] = function(fn) { return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };\n\n})(jQuery, 'smartresize');\n\n\njQuery(document).ready(function() {\n    jQuery('#sidebar .category-icon').on('click', function() {\n        $( this ).toggleClass(\"fa-angle-down fa-angle-right\") ;\n        $( this ).parent().parent().children('ul').toggle() ;\n        return false;\n    });\n\n    var sidebarStatus = searchStatus = 'open';\n    $('#sidebar .highlightable').perfectScrollbar();\n    setMenuHeight();\n\n    jQuery('#overlay').on('click', function() {\n        jQuery(document.body).toggleClass('sidebar-hidden');\n        sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open');\n\n        return false;\n    });\n\n    jQuery('[data-sidebar-toggle]').on('click', function() {\n        jQuery(document.body).toggleClass('sidebar-hidden');\n        sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open');\n\n        return false;\n    });\n    jQuery('[data-clear-history-toggle]').on('click', function() {\n        sessionStorage.clear();\n        location.reload();\n        return false;\n    });\n    jQuery('[data-search-toggle]').on('click', function() {\n        if (sidebarStatus == 'closed') {\n            jQuery('[data-sidebar-toggle]').trigger('click');\n            jQuery(document.body).removeClass('searchbox-hidden');\n            searchStatus = 'open';\n\n            return false;\n        }\n\n        jQuery(document.body).toggleClass('searchbox-hidden');\n        searchStatus = (jQuery(document.body).hasClass('searchbox-hidden') ? 'closed' : 'open');\n\n        return false;\n    });\n\n    var ajax;\n    jQuery('[data-search-input]').on('input', function() {\n        var input = jQuery(this),\n            value = input.val(),\n            items = jQuery('[data-nav-id]');\n        items.removeClass('search-match');\n        if (!value.length) {\n            $('ul.topics').removeClass('searched');\n            items.css('display', 'block');\n            sessionStorage.removeItem('search-value');\n            $(\".highlightable\").unhighlight({ element: 'mark' })\n            return;\n        }\n\n        sessionStorage.setItem('search-value', value);\n        $(\".highlightable\").unhighlight({ element: 'mark' }).highlight(value, { element: 'mark' });\n\n        if (ajax && ajax.abort) ajax.abort();\n\n        jQuery('[data-search-clear]').on('click', function() {\n            jQuery('[data-search-input]').val('').trigger('input');\n            sessionStorage.removeItem('search-input');\n            $(\".highlightable\").unhighlight({ element: 'mark' })\n        });\n    });\n\n    $.expr[\":\"].contains = $.expr.createPseudo(function(arg) {\n        return function( elem ) {\n            return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;\n        };\n    });\n\n    if (sessionStorage.getItem('search-value')) {\n        var searchValue = sessionStorage.getItem('search-value')\n        $(document.body).removeClass('searchbox-hidden');\n        $('[data-search-input]').val(searchValue);\n        $('[data-search-input]').trigger('input');\n        var searchedElem = $('#body-inner').find(':contains(' + searchValue + ')').get(0);\n        if (searchedElem) {\n            searchedElem.scrollIntoView(true);\n            var scrolledY = window.scrollY;\n            if(scrolledY){\n                window.scroll(0, scrolledY - 125);\n            }\n        }\n    }\n\n    // clipboard\n    var clipInit = false;\n    $('code').each(function() {\n        var code = $(this),\n            text = code.text();\n\n        if (text.length > 5) {\n            if (!clipInit) {\n                var text, clip = new Clipboard('.copy-to-clipboard', {\n                    text: function(trigger) {\n                        text = $(trigger).prev('code').text();\n                        return text.replace(/^\\$\\s/gm, '');\n                    }\n                });\n\n                var inPre;\n                clip.on('success', function(e) {\n                    e.clearSelection();\n                    inPre = $(e.trigger).parent().prop('tagName') == 'PRE';\n                    $(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));\n                });\n\n                clip.on('error', function(e) {\n                    inPre = $(e.trigger).parent().prop('tagName') == 'PRE';\n                    $(e.trigger).attr('aria-label', fallbackMessage(e.action)).addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));\n                    $(document).one('copy', function(){\n                        $(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));\n                    });\n                });\n\n                clipInit = true;\n            }\n\n            code.after('<span class=\"copy-to-clipboard\" title=\"Copy to clipboard\" />');\n            code.next('.copy-to-clipboard').on('mouseleave', function() {\n                $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w');\n            });\n        }\n    });\n\n    // allow keyboard control for prev/next links\n    jQuery(function() {\n        jQuery('.nav-prev').click(function(){\n            location.href = jQuery(this).attr('href');\n        });\n        jQuery('.nav-next').click(function() {\n            location.href = jQuery(this).attr('href');\n        });\n    });\n\n    jQuery(document).keydown(function(e) {\n      // prev links - left arrow key\n      if(e.which == '37') {\n        jQuery('.nav.nav-prev').click();\n      }\n\n      // next links - right arrow key\n      if(e.which == '39') {\n        jQuery('.nav.nav-next').click();\n      }\n    });\n\n    $('#top-bar a:not(:has(img)):not(.btn)').addClass('highlight');\n    $('#body-inner a:not(:has(img)):not(.btn):not(a[rel=\"footnote\"])').addClass('highlight');\n\n    var touchsupport = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)\n    if (!touchsupport){ // browser doesn't support touch\n        $('#toc-menu').hover(function() {\n            $('.progress').stop(true, false, true).fadeToggle(100);\n        });\n\n        $('.progress').hover(function() {\n            $('.progress').stop(true, false, true).fadeToggle(100);\n        });\n    }\n    if (touchsupport){ // browser does support touch\n        $('#toc-menu').click(function() {\n            $('.progress').stop(true, false, true).fadeToggle(100);\n        });\n        $('.progress').click(function() {\n            $('.progress').stop(true, false, true).fadeToggle(100);\n        });\n    }\n\n    /** \n    * Fix anchor scrolling that hides behind top nav bar\n    * Courtesy of https://stackoverflow.com/a/13067009/28106\n    *\n    * We could use pure css for this if only heading anchors were\n    * involved, but this works for any anchor, including footnotes\n    **/\n    (function (document, history, location) {\n        var HISTORY_SUPPORT = !!(history && history.pushState);\n\n        var anchorScrolls = {\n            ANCHOR_REGEX: /^#[^ ]+$/,\n            OFFSET_HEIGHT_PX: 50,\n\n            /**\n             * Establish events, and fix initial scroll position if a hash is provided.\n             */\n            init: function () {\n                this.scrollToCurrent();\n                $(window).on('hashchange', $.proxy(this, 'scrollToCurrent'));\n                $('body').on('click', 'a', $.proxy(this, 'delegateAnchors'));\n            },\n\n            /**\n             * Return the offset amount to deduct from the normal scroll position.\n             * Modify as appropriate to allow for dynamic calculations\n             */\n            getFixedOffset: function () {\n                return this.OFFSET_HEIGHT_PX;\n            },\n\n            /**\n             * If the provided href is an anchor which resolves to an element on the\n             * page, scroll to it.\n             * @param  {String} href\n             * @return {Boolean} - Was the href an anchor.\n             */\n            scrollIfAnchor: function (href, pushToHistory) {\n                var match, anchorOffset;\n\n                if (!this.ANCHOR_REGEX.test(href)) {\n                    return false;\n                }\n\n                match = document.getElementById(href.slice(1));\n\n                if (match) {\n                    anchorOffset = $(match).offset().top - this.getFixedOffset();\n                    $('html, body').animate({ scrollTop: anchorOffset });\n\n                    // Add the state to history as-per normal anchor links\n                    if (HISTORY_SUPPORT && pushToHistory) {\n                        history.pushState({}, document.title, location.pathname + href);\n                    }\n                }\n\n                return !!match;\n            },\n\n            /**\n             * Attempt to scroll to the current location's hash.\n             */\n            scrollToCurrent: function (e) {\n                if (this.scrollIfAnchor(window.location.hash) && e) {\n                    e.preventDefault();\n                }\n            },\n\n            /**\n             * If the click event's target was an anchor, fix the scroll position.\n             */\n            delegateAnchors: function (e) {\n                var elem = e.target;\n\n                if (this.scrollIfAnchor(elem.getAttribute('href'), true)) {\n                    e.preventDefault();\n                }\n            }\n        };\n\n        $(document).ready($.proxy(anchorScrolls, 'init'));\n    })(window.document, window.history, window.location);\n    \n});\n\njQuery(window).on('load', function() {\n\n    function adjustForScrollbar() {\n        if ((parseInt(jQuery('#body-inner').height()) + 83) >= jQuery('#body').height()) {\n            jQuery('.nav.nav-next').css({ 'margin-right': getScrollBarWidth() });\n        } else {\n            jQuery('.nav.nav-next').css({ 'margin-right': 0 });\n        }\n    }\n\n    // adjust sidebar for scrollbar\n    adjustForScrollbar();\n\n    jQuery(window).smartresize(function() {\n        adjustForScrollbar();\n    });\n\n    // store this page in session\n    sessionStorage.setItem(jQuery('body').data('url'), 1);\n\n    // loop through the sessionStorage and see if something should be marked as visited\n    for (var url in sessionStorage) {\n        if (sessionStorage.getItem(url) == 1) jQuery('[data-nav-id=\"' + url + '\"]').addClass('visited');\n    }\n\n\n    $(\".highlightable\").highlight(sessionStorage.getItem('search-value'), { element: 'mark' });\n});\n\n$(function() {\n    $('a[rel=\"lightbox\"]').featherlight({\n        root: 'section#body'\n    });\n\n    var logo = $('header img')\n    var logosrc = logo.attr('src')\n    var loadTheme = localStorage.getItem('ss-theme')\n    if(loadTheme){\n        $('body').attr(\"class\", loadTheme+'-theme');\n        $('.change-theme span').removeClass('active')\n        $('.change-theme span[data-item='+loadTheme+']').addClass('active')\n        $('.change-theme span[data-item='+loadTheme+']').addClass(loadTheme)\n    }  \n    // if(/dark|deep/.test(loadTheme)){\n    //     logo.attr('src', logosrc.replace('logo_v3','logo_v2'))\n    // }else{\n    //     logo.attr('src', logosrc.replace('logo_v2','logo_v3'))\n    // }\n\n    $('.change-theme span').click(function(){\n        var _this = $(this),\n        theme =  _this.data('item')\n        if(theme){\n            $('body').attr(\"class\", theme+'-theme');\n            localStorage.setItem('ss-theme', theme)\n        }else{\n            $('body').attr(\"class\", '');\n            localStorage.setItem('ss-theme', '')\n        }\n        // if(/dark|deep/.test(theme)){\n        //     logo.attr('src', logosrc.replace('logo_v3','logo_v2'))\n        // }else{\n        //     logo.attr('src', logosrc.replace('logo_v2','logo_v3'))\n        // }\n        _this.addClass('active')\n        _this.addClass(theme)\n        _this.siblings().attr('class','')\n    })\n});\n\nwindow.onload = function(){\n    var markdown = document.querySelector('#body'),\n    h2s = markdown.querySelectorAll('h2'),\n    bookToc = document.querySelector('#TableOfContents');\n    if(bookToc){\n      var bocs = bookToc.querySelectorAll('a'),\n      h2Info = [];\n      h2s.forEach(item=>{\n        h2Info.push({\n          top: item.offsetTop,\n          id: item.id\n        })\n      })\n      \n      function ScollPostion() {\n        var t, l, w, h;\n        if (document.documentElement && document.documentElement.scrollTop) {\n            t = document.documentElement.scrollTop;\n            l = document.documentElement.scrollLeft;\n            w = document.documentElement.scrollWidth;\n            h = document.documentElement.scrollHeight;\n        } else if (document.body) {\n            t = document.body.scrollTop;\n            l = document.body.scrollLeft;\n            w = document.body.scrollWidth;\n            h = document.body.scrollHeight;\n        }\n        return {\n            top: t,\n            left: l,\n            width: w,\n            height: h\n        };\n    }\n\n      function deal(str){\n        bocs.forEach(function(item){\n          if(item.getAttribute('href').split('#')[1] == str){\n            // console.log(item, str)\n            item.classList='active'\n          }else{\n            item.classList=''\n          }\n        })\n      }\n\n      document.body.onscroll = function(e){\n        var scrollTop = ScollPostion().top\n        h2Info.map(function(item){\n          if(Math.abs(scrollTop - item.top)<20){\n            deal(item.id)\n          }\n        })\n      }\n    }\n    \n  }\n\njQuery.extend({\n    highlight: function(node, re, nodeName, className) {\n        if (node.nodeType === 3) {\n            var match = node.data.match(re);\n            if (match) {\n                var highlight = document.createElement(nodeName || 'span');\n                highlight.className = className || 'highlight';\n                var wordNode = node.splitText(match.index);\n                wordNode.splitText(match[0].length);\n                var wordClone = wordNode.cloneNode(true);\n                highlight.appendChild(wordClone);\n                wordNode.parentNode.replaceChild(highlight, wordNode);\n                return 1; //skip added node in parent\n            }\n        } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children\n            !/(script|style)/i.test(node.tagName) && // ignore script and style nodes\n            !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted\n            for (var i = 0; i < node.childNodes.length; i++) {\n                i += jQuery.highlight(node.childNodes[i], re, nodeName, className);\n            }\n        }\n        return 0;\n    }\n});\n\njQuery.fn.unhighlight = function(options) {\n    var settings = {\n        className: 'highlight',\n        element: 'span'\n    };\n    jQuery.extend(settings, options);\n\n    return this.find(settings.element + \".\" + settings.className).each(function() {\n        var parent = this.parentNode;\n        parent.replaceChild(this.firstChild, this);\n        parent.normalize();\n    }).end();\n};\n\njQuery.fn.highlight = function(words, options) {\n    var settings = {\n        className: 'highlight',\n        element: 'span',\n        caseSensitive: false,\n        wordsOnly: false\n    };\n    jQuery.extend(settings, options);\n\n    if (!words) { return; }\n\n    if (words.constructor === String) {\n        words = [words];\n    }\n    words = jQuery.grep(words, function(word, i) {\n        return word != '';\n    });\n    words = jQuery.map(words, function(word, i) {\n        return word.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, \"\\\\$&\");\n    });\n    if (words.length == 0) { return this; }\n    ;\n\n    var flag = settings.caseSensitive ? \"\" : \"i\";\n    var pattern = \"(\" + words.join(\"|\") + \")\";\n    if (settings.wordsOnly) {\n        pattern = \"\\\\b\" + pattern + \"\\\\b\";\n    }\n    var re = new RegExp(pattern, flag);\n\n    return this.each(function() {\n        jQuery.highlight(this, re, settings.element, settings.className);\n    });\n};\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/js/modernizr.custom.71422.js",
    "content": "/* Modernizr 2.7.1 (Custom Build) | MIT & BSD\n * Build: http://modernizr.com/download/#-csstransforms3d-shiv-cssclasses-teststyles-testprop-testallprops-prefixes-domprefixes-load\n */\n;window.Modernizr=function(a,b,c){function z(a){j.cssText=a}function A(a,b){return z(m.join(a+\";\")+(b||\"\"))}function B(a,b){return typeof a===b}function C(a,b){return!!~(\"\"+a).indexOf(b)}function D(a,b){for(var d in a){var e=a[d];if(!C(e,\"-\")&&j[e]!==c)return b==\"pfx\"?e:!0}return!1}function E(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:B(f,\"function\")?f.bind(d||b):f}return!1}function F(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+\" \"+o.join(d+\" \")+d).split(\" \");return B(b,\"string\")||B(b,\"undefined\")?D(e,b):(e=(a+\" \"+p.join(d+\" \")+d).split(\" \"),E(e,b,c))}var d=\"2.7.1\",e={},f=!0,g=b.documentElement,h=\"modernizr\",i=b.createElement(h),j=i.style,k,l={}.toString,m=\" -webkit- -moz- -o- -ms- \".split(\" \"),n=\"Webkit Moz O ms\",o=n.split(\" \"),p=n.toLowerCase().split(\" \"),q={},r={},s={},t=[],u=t.slice,v,w=function(a,c,d,e){var f,i,j,k,l=b.createElement(\"div\"),m=b.body,n=m||b.createElement(\"body\");if(parseInt(d,10))while(d--)j=b.createElement(\"div\"),j.id=e?e[d]:h+(d+1),l.appendChild(j);return f=[\"&#173;\",'<style id=\"s',h,'\">',a,\"</style>\"].join(\"\"),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background=\"\",n.style.overflow=\"hidden\",k=g.style.overflow,g.style.overflow=\"hidden\",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},x={}.hasOwnProperty,y;!B(x,\"undefined\")&&!B(x.call,\"undefined\")?y=function(a,b){return x.call(a,b)}:y=function(a,b){return b in a&&B(a.constructor.prototype[b],\"undefined\")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!=\"function\")throw new TypeError;var d=u.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(u.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(u.call(arguments)))};return e}),q.csstransforms3d=function(){var a=!!F(\"perspective\");return a&&\"webkitPerspective\"in g.style&&w(\"@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}\",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a};for(var G in q)y(q,G)&&(v=G.toLowerCase(),e[v]=q[G](),t.push((e[v]?\"\":\"no-\")+v));return e.addTest=function(a,b){if(typeof a==\"object\")for(var d in a)y(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b==\"function\"?b():b,typeof f!=\"undefined\"&&f&&(g.className+=\" \"+(b?\"\":\"no-\")+a),e[a]=b}return e},z(\"\"),i=k=null,function(a,b){function l(a,b){var c=a.createElement(\"p\"),d=a.getElementsByTagName(\"head\")[0]||a.documentElement;return c.innerHTML=\"x<style>\"+b+\"</style>\",d.insertBefore(c.lastChild,d.firstChild)}function m(){var a=s.elements;return typeof a==\"string\"?a.split(\" \"):a}function n(a){var b=j[a[h]];return b||(b={},i++,a[h]=i,j[i]=b),b}function o(a,c,d){c||(c=b);if(k)return c.createElement(a);d||(d=n(c));var g;return d.cache[a]?g=d.cache[a].cloneNode():f.test(a)?g=(d.cache[a]=d.createElem(a)).cloneNode():g=d.createElem(a),g.canHaveChildren&&!e.test(a)&&!g.tagUrn?d.frag.appendChild(g):g}function p(a,c){a||(a=b);if(k)return a.createDocumentFragment();c=c||n(a);var d=c.frag.cloneNode(),e=0,f=m(),g=f.length;for(;e<g;e++)d.createElement(f[e]);return d}function q(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return s.shivMethods?o(c,a,b):b.createElem(c)},a.createDocumentFragment=Function(\"h,f\",\"return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&(\"+m().join().replace(/[\\w\\-]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c(\"'+a+'\")'})+\");return n}\")(s,b.frag)}function r(a){a||(a=b);var c=n(a);return s.shivCSS&&!g&&!c.hasCSS&&(c.hasCSS=!!l(a,\"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}\")),k||q(a,c),a}var c=\"3.7.0\",d=a.html5||{},e=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,f=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,g,h=\"_html5shiv\",i=0,j={},k;(function(){try{var a=b.createElement(\"a\");a.innerHTML=\"<xyz></xyz>\",g=\"hidden\"in a,k=a.childNodes.length==1||function(){b.createElement(\"a\");var a=b.createDocumentFragment();return typeof a.cloneNode==\"undefined\"||typeof a.createDocumentFragment==\"undefined\"||typeof a.createElement==\"undefined\"}()}catch(c){g=!0,k=!0}})();var s={elements:d.elements||\"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video\",version:c,shivCSS:d.shivCSS!==!1,supportsUnknownElements:k,shivMethods:d.shivMethods!==!1,type:\"default\",shivDocument:r,createElement:o,createDocumentFragment:p};a.html5=s,r(b)}(this,b),e._version=d,e._prefixes=m,e._domPrefixes=p,e._cssomPrefixes=o,e.testProp=function(a){return D([a])},e.testAllProps=F,e.testStyles=w,g.className=g.className.replace(/(^|\\s)no-js(\\s|$)/,\"$1$2\")+(f?\" js \"+t.join(\" \"):\"\"),e}(this,this.document),function(a,b,c){function d(a){return\"[object Function]\"==o.call(a)}function e(a){return\"string\"==typeof a}function f(){}function g(a){return!a||\"loaded\"==a||\"complete\"==a||\"uninitialized\"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){(\"c\"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){\"img\"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),\"object\"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height=\"0\",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),\"img\"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||\"j\",e(a)?i(\"c\"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName(\"script\")[0],o={}.toString,p=[],q=0,r=\"MozAppearance\"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&\"[object Opera]\"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?\"object\":l?\"script\":\"img\",v=l?\"script\":u,w=Array.isArray||function(a){return\"[object Array]\"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split(\"!\"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f<d;f++)g=a[f].split(\"=\"),(e=z[g.shift()])&&(c=e(c,g));for(f=0;f<b;f++)c=x[f](c);return c}function g(a,e,f,g,h){var i=b(a),j=i.autoCallback;i.url.split(\".\").pop().split(\"?\").shift(),i.bypass||(e&&(e=d(e)?e:e[a]||e[g]||e[a.split(\"/\").pop().split(\"?\")[0]]),i.instead?i.instead(a,e,f,g,h):(y[i.url]?i.noexec=!0:y[i.url]=1,f.load(i.url,i.forceCSS||!i.forceJS&&\"css\"==i.url.split(\".\").pop().split(\"?\").shift()?\"c\":c,i.noexec,i.attrs,i.timeout),(d(e)||d(j))&&f.load(function(){k(),e&&e(i.origUrl,h,g),j&&j(i.origUrl,h,g),y[i.url]=2})))}function h(a,b){function c(a,c){if(a){if(e(a))c||(j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}),g(a,j,b,0,h);else if(Object(a)===a)for(n in m=function(){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b}(),a)a.hasOwnProperty(n)&&(!c&&!--m&&(d(j)?j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}:j[n]=function(a){return function(){var b=[].slice.call(arguments);a&&a.apply(this,b),l()}}(k[n])),g(a[n],j,b,n,h))}else!c&&l()}var h=!!a.test,i=a.load||a.both,j=a.callback||f,k=j,l=a.complete||f,m,n;c(h?a.yep:a.nope,!!i),i&&c(i)}var i,j,l=this.yepnope.loader;if(e(a))g(a,0,l,0);else if(w(a))for(i=0;i<a.length;i++)j=a[i],e(j)?g(j,0,l,0):w(j)?B(j):Object(j)===j&&h(j,l);else Object(a)===a&&h(a,l)},B.addPrefix=function(a,b){z[a]=b},B.addFilter=function(a){x.push(a)},B.errorTimeout=1e4,null==b.readyState&&b.addEventListener&&(b.readyState=\"loading\",b.addEventListener(\"DOMContentLoaded\",A=function(){b.removeEventListener(\"DOMContentLoaded\",A,0),b.readyState=\"complete\"},0)),a.yepnope=k(),a.yepnope.executeStack=h,a.yepnope.injectJs=function(a,c,d,e,i,j){var k=b.createElement(\"script\"),l,o,e=e||B.errorTimeout;k.src=a;for(o in d)k.setAttribute(o,d[o]);c=j?h:c||f,k.onreadystatechange=k.onload=function(){!l&&g(k.readyState)&&(l=1,c(),k.onload=k.onreadystatechange=null)},m(function(){l||(l=1,c(1))},e),i?k.onload():n.parentNode.insertBefore(k,n)},a.yepnope.injectCss=function(a,c,d,e,g,i){var e=b.createElement(\"link\"),j,c=i?h:c||f;e.href=a,e.rel=\"stylesheet\",e.type=\"text/css\";for(j in d)e.setAttribute(j,d[j]);g||(n.parentNode.insertBefore(e,n),m(c,0))}}(this,document),Modernizr.load=function(){yepnope.apply(window,[].slice.call(arguments,0))};"
  },
  {
    "path": "docs/themes/hugo-theme-learn/static/js/search.js",
    "content": "var lunrIndex, pagesIndex;\n\nfunction endsWith(str, suffix) {\n    return str.indexOf(suffix, str.length - suffix.length) !== -1;\n}\n\n// Initialize lunrjs using our generated index file\nfunction initLunr() {\n    if (!endsWith(baseurl,\"/\")){\n        baseurl = baseurl+'/'\n    };\n\n    // First retrieve the index file\n    $.getJSON(baseurl +\"index.json\")\n        .done(function(index) {\n            pagesIndex =   index;\n            // Set up lunrjs by declaring the fields we use\n            // Also provide their boost level for the ranking\n            lunrIndex = new lunr.Index\n            lunrIndex.ref(\"uri\");\n            lunrIndex.field('title', {\n                boost: 15\n            });\n            lunrIndex.field('tags', {\n                boost: 10\n            });\n            lunrIndex.field(\"content\", {\n                boost: 5\n            });\n\n            // Feed lunr with each file and let lunr actually index them\n            pagesIndex.forEach(function(page) {\n                lunrIndex.add(page);\n            });\n            lunrIndex.pipeline.remove(lunrIndex.stemmer)\n        })\n        .fail(function(jqxhr, textStatus, error) {\n            var err = textStatus + \", \" + error;\n            console.error(\"Error getting Hugo index flie:\", err);\n        });\n}\n\n/**\n * Trigger a search in lunr and transform the result\n *\n * @param  {String} query\n * @return {Array}  results\n */\nfunction search(query) {\n    // Find the item in our index corresponding to the lunr one to have more info\n    return lunrIndex.search(query).map(function(result) {\n            return pagesIndex.filter(function(page) {\n                return page.uri === result.ref;\n            })[0];\n        });\n}\n\n// Let's get started\ninitLunr();\n$( document ).ready(function() {\n    var searchList = new autoComplete({\n        /* selector for the search box element */\n        selector: $(\"#search-by\").get(0),\n        /* source is the callback to perform the search */\n        source: function(term, response) {\n            response(search(term));\n        },\n        /* renderItem displays individual search results */\n        renderItem: function(item, term) {\n            var numContextWords = 2;\n            var text = item.content.match(\n                \"(?:\\\\s?(?:[\\\\w]+)\\\\s?){0,\"+numContextWords+\"}\" +\n                    term+\"(?:\\\\s?(?:[\\\\w]+)\\\\s?){0,\"+numContextWords+\"}\");\n            item.context = text;\n            return '<div class=\"autocomplete-suggestion\" ' +\n                'data-term=\"' + term + '\" ' +\n                'data-title=\"' + item.title + '\" ' +\n                'data-uri=\"'+ item.uri + '\" ' +\n                'data-context=\"' + item.context + '\">' +\n                '» ' + item.title +\n                '<div class=\"context\">' +\n                (item.context || '') +'</div>' +\n                '</div>';\n        },\n        /* onSelect callback fires when a search suggestion is chosen */\n        onSelect: function(e, term, item) {\n            location.href = item.getAttribute('data-uri');\n        }\n    });\n});\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/theme.toml",
    "content": "# theme.toml template for a Hugo theme\n# See https://github.com/spf13/hugoThemes#themetoml for an example\n\nname = \"Learn\"\nlicense = \"MIT\"\nlicenselink = \"https://github.com/matcornic/hugo-theme-learn/blob/master/LICENSE.md\"\ndescription = \"Documentation theme for Hugo, based on Grav Learn theme\"\nhomepage = \"https://github.com/matcornic/hugo-theme-learn/\"\nrepo = \"https://github.com/matcornic/hugo-theme-learn\"\ntags = [\"documentation\", \"grav\", \"learn\", \"doc\", \"search\"]\nfeatures = [\"documentation\", \"menu\", \"nested sections\", \"search\", \"mermaid\"]\nmin_version = 0.25\n\n[author]\n  name = \"Mathieu Cornic\"\n  homepage = \"http://matcornic.github.io/\"\n\n[original]\n  name = \"Grav Learn\"\n  homepage = \"http://learn.getgrav.org/\"\n  repo = \"https://github.com/getgrav/grav-learn\"\n\n"
  },
  {
    "path": "docs/themes/hugo-theme-learn/wercker.yml",
    "content": "box: golang\nbuild:\n  steps:\n    # Sets the go workspace and places you package\n    # at the right place in the workspace tree\n    - setup-go-workspace\n\n    # Gets the dependencies\n    - script:\n        name: get hugo\n        code: |\n          go get github.com/gohugoio/hugo\n\n    # Build the project\n    - script:\n        name: build site\n        code: |\n          cd exampleSite && hugo"
  },
  {
    "path": "ecosystem/error-handler/dingtalk/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-error-handler</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-restful</artifactId>\n            <version>${project.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpclient</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpcore</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "ecosystem/error-handler/dingtalk/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/dingtalk/DingtalkJobErrorHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.dingtalk;\n\nimport com.google.common.base.Strings;\nimport com.google.common.collect.ImmutableMap;\nimport com.google.gson.JsonObject;\nimport lombok.SneakyThrows;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.util.EntityUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.json.GsonFactory;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\n\nimport javax.crypto.Mac;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.io.UnsupportedEncodingException;\nimport java.net.HttpURLConnection;\nimport java.net.URLEncoder;\nimport java.nio.charset.StandardCharsets;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.Properties;\n\n/**\n * Job error handler for send error message via Dingtalk.\n */\n@Slf4j\npublic final class DingtalkJobErrorHandler implements JobErrorHandler {\n    \n    private final CloseableHttpClient httpclient = HttpClients.createDefault();\n    \n    private String webhook;\n    \n    private String keyword;\n    \n    private String secret;\n    \n    private int connectTimeoutMilliseconds;\n    \n    private int readTimeoutMilliseconds;\n    \n    @Override\n    public void init(final Properties props) {\n        webhook = props.getProperty(DingtalkPropertiesConstants.WEBHOOK);\n        keyword = props.getProperty(DingtalkPropertiesConstants.KEYWORD);\n        secret = props.getProperty(DingtalkPropertiesConstants.SECRET);\n        connectTimeoutMilliseconds = Integer.parseInt(props.getProperty(DingtalkPropertiesConstants.CONNECT_TIMEOUT_MILLISECONDS, DingtalkPropertiesConstants.DEFAULT_CONNECT_TIMEOUT_MILLISECONDS));\n        readTimeoutMilliseconds = Integer.parseInt(props.getProperty(DingtalkPropertiesConstants.READ_TIMEOUT_MILLISECONDS, DingtalkPropertiesConstants.DEFAULT_READ_TIMEOUT_MILLISECONDS));\n    }\n    \n    @Override\n    public void handleException(final String jobName, final Throwable cause) {\n        HttpPost httpPost = createHTTPPostMethod(jobName, cause);\n        try (CloseableHttpResponse response = httpclient.execute(httpPost)) {\n            int status = response.getStatusLine().getStatusCode();\n            if (HttpURLConnection.HTTP_OK == status) {\n                JsonObject responseMessage = GsonFactory.getGson().fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class);\n                if (!\"0\".equals(responseMessage.get(\"errcode\").getAsString())) {\n                    log.error(\"An exception has occurred in Job '{}' but failed to send dingtalk because of: {}\", jobName, responseMessage.get(\"errmsg\").getAsString(), cause);\n                } else {\n                    log.info(\"An exception has occurred in Job '{}', an dingtalk message been sent successful.\", jobName, cause);\n                }\n            } else {\n                log.error(\"An exception has occurred in Job '{}' but failed to send dingtalk because of: unexpected http response status: {}\", jobName, status, cause);\n            }\n        } catch (final IOException ex) {\n            cause.addSuppressed(ex);\n            log.error(\"An exception has occurred in Job '{}', but failed to send dingtalk because of\", jobName, cause);\n        }\n    }\n    \n    private HttpPost createHTTPPostMethod(final String jobName, final Throwable cause) {\n        HttpPost result = new HttpPost(getURL());\n        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeoutMilliseconds).setSocketTimeout(readTimeoutMilliseconds).build();\n        result.setConfig(requestConfig);\n        StringEntity entity = new StringEntity(getJsonParameter(getErrorMessage(jobName, cause)), StandardCharsets.UTF_8);\n        entity.setContentEncoding(StandardCharsets.UTF_8.name());\n        entity.setContentType(\"application/json\");\n        result.setEntity(entity);\n        return result;\n    }\n    \n    private String getURL() {\n        return Strings.isNullOrEmpty(secret) ? webhook : getSignedURL();\n    }\n    \n    private String getSignedURL() {\n        long timestamp = System.currentTimeMillis();\n        return String.format(\"%s&timestamp=%s&sign=%s\", webhook, timestamp, generateSignature(timestamp));\n    }\n    \n    @SneakyThrows({NoSuchAlgorithmException.class, UnsupportedEncodingException.class, InvalidKeyException.class})\n    private String generateSignature(final long timestamp) {\n        String algorithmName = \"HmacSHA256\";\n        Mac mac = Mac.getInstance(algorithmName);\n        mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), algorithmName));\n        byte[] signData = mac.doFinal((timestamp + \"\\n\" + secret).getBytes(StandardCharsets.UTF_8));\n        return URLEncoder.encode(new String(Base64.getEncoder().encode(signData)), StandardCharsets.UTF_8.name());\n    }\n    \n    private String getJsonParameter(final String message) {\n        return GsonFactory.getGson().toJson(ImmutableMap.of(\"msgtype\", \"text\", \"text\", Collections.singletonMap(\"content\", message)));\n    }\n    \n    private String getErrorMessage(final String jobName, final Throwable cause) {\n        StringWriter writer = new StringWriter();\n        cause.printStackTrace(new PrintWriter(writer, true));\n        String result = String.format(\"Job '%s' exception occur in job processing, caused by %s\", jobName, writer);\n        if (!Strings.isNullOrEmpty(keyword)) {\n            result = keyword.concat(result);\n        }\n        return result;\n    }\n    \n    @Override\n    public String getType() {\n        return \"DINGTALK\";\n    }\n    \n    @SneakyThrows(IOException.class)\n    @Override\n    public void close() {\n        httpclient.close();\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/dingtalk/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/dingtalk/DingtalkJobErrorHandlerPropertiesValidator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.dingtalk;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.PropertiesPreconditions;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandlerPropertiesValidator;\n\nimport java.util.Properties;\n\n/**\n * Job error handler properties validator for Dingtalk.\n */\npublic final class DingtalkJobErrorHandlerPropertiesValidator implements JobErrorHandlerPropertiesValidator {\n    \n    @Override\n    public void validate(final Properties props) {\n        PropertiesPreconditions.checkRequired(props, DingtalkPropertiesConstants.WEBHOOK);\n        PropertiesPreconditions.checkPositiveInteger(props, DingtalkPropertiesConstants.CONNECT_TIMEOUT_MILLISECONDS);\n        PropertiesPreconditions.checkPositiveInteger(props, DingtalkPropertiesConstants.READ_TIMEOUT_MILLISECONDS);\n    }\n    \n    @Override\n    public String getType() {\n        return \"DINGTALK\";\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/dingtalk/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/dingtalk/DingtalkPropertiesConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.dingtalk;\n\n/**\n * Job error handler properties constants for send error message via Dingtalk.\n */\npublic final class DingtalkPropertiesConstants {\n    \n    public static final String DEFAULT_CONNECT_TIMEOUT_MILLISECONDS = \"3000\";\n    \n    public static final String DEFAULT_READ_TIMEOUT_MILLISECONDS = \"5000\";\n    \n    private static final String PREFIX = \"dingtalk.\";\n    \n    public static final String WEBHOOK = PREFIX + \"webhook\";\n    \n    public static final String KEYWORD = PREFIX + \"keyword\";\n    \n    public static final String SECRET = PREFIX + \"secret\";\n    \n    public static final String CONNECT_TIMEOUT_MILLISECONDS = PREFIX + \"connectTimeoutMilliseconds\";\n    \n    public static final String READ_TIMEOUT_MILLISECONDS = PREFIX + \"readTimeoutMilliseconds\";\n}\n"
  },
  {
    "path": "ecosystem/error-handler/dingtalk/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.error.handler.dingtalk.DingtalkJobErrorHandler\n"
  },
  {
    "path": "ecosystem/error-handler/dingtalk/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandlerPropertiesValidator",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.error.handler.dingtalk.DingtalkJobErrorHandlerPropertiesValidator\n"
  },
  {
    "path": "ecosystem/error-handler/dingtalk/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/dingtalk/DingtalkJobErrorHandlerPropertiesValidatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.dingtalk;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandlerPropertiesValidator;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass DingtalkJobErrorHandlerPropertiesValidatorTest {\n    \n    @Test\n    void assertValidateWithNormal() {\n        Properties properties = new Properties();\n        properties.setProperty(DingtalkPropertiesConstants.WEBHOOK, \"webhook\");\n        properties.setProperty(DingtalkPropertiesConstants.READ_TIMEOUT_MILLISECONDS, \"1000\");\n        properties.setProperty(DingtalkPropertiesConstants.CONNECT_TIMEOUT_MILLISECONDS, \"2000\");\n        TypedSPILoader.getService(JobErrorHandlerPropertiesValidator.class, \"DINGTALK\").validate(properties);\n    }\n    \n    @Test\n    void assertValidateWithPropsIsNull() {\n        assertThrows(NullPointerException.class, () -> TypedSPILoader.getService(JobErrorHandlerPropertiesValidator.class, \"DINGTALK\").validate(null));\n    }\n    \n    @Test\n    void assertValidateWithWebhookIsNull() {\n        try {\n            TypedSPILoader.getService(JobErrorHandlerPropertiesValidator.class, \"DINGTALK\").validate(new Properties());\n        } catch (final IllegalArgumentException ex) {\n            assertThat(ex.getMessage(), is(String.format(\"The property `%s` is required.\", DingtalkPropertiesConstants.WEBHOOK)));\n        }\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/dingtalk/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/dingtalk/DingtalkJobErrorHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.dingtalk;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.core.read.ListAppender;\nimport org.apache.curator.test.InstanceSpec;\nimport org.apache.shardingsphere.elasticjob.error.handler.dingtalk.fixture.DingtalkInternalController;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulService;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulServiceConfiguration;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulService;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.List;\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass DingtalkJobErrorHandlerTest {\n    \n    private static final int PORT = InstanceSpec.getRandomPort();\n    \n    private static final String HOST = \"localhost\";\n    \n    private static RestfulService restfulService;\n    \n    private static List<LoggingEvent> appenderList;\n    \n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    @BeforeAll\n    static void init() {\n        NettyRestfulServiceConfiguration config = new NettyRestfulServiceConfiguration(PORT);\n        config.setHost(HOST);\n        config.addControllerInstances(new DingtalkInternalController());\n        restfulService = new NettyRestfulService(config);\n        restfulService.startup();\n        ch.qos.logback.classic.Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(DingtalkJobErrorHandler.class);\n        ListAppender<LoggingEvent> appender = (ListAppender) log.getAppender(\"DingtalkJobErrorHandlerTestAppender\");\n        appenderList = appender.list;\n    }\n    \n    @BeforeEach\n    void setUp() {\n        appenderList.clear();\n    }\n    \n    @AfterAll\n    static void close() {\n        if (null != restfulService) {\n            restfulService.shutdown();\n        }\n    }\n    \n    @Test\n    void assertHandleExceptionWithNotifySuccessful() {\n        DingtalkJobErrorHandler actual = getDingtalkJobErrorHandler(createConfigurationProperties(\"http://localhost:\" + PORT + \"/send?access_token=mocked_token\"));\n        Throwable cause = new RuntimeException(\"test\");\n        actual.handleException(\"test_job\", cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.INFO));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job', an dingtalk message been sent successful.\"));\n    }\n    \n    @Test\n    void assertHandleExceptionWithWrongToken() {\n        DingtalkJobErrorHandler actual = getDingtalkJobErrorHandler(createConfigurationProperties(\"http://localhost:\" + PORT + \"/send?access_token=wrong_token\"));\n        Throwable cause = new RuntimeException(\"test\");\n        actual.handleException(\"test_job\", cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.ERROR));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job' but failed to send dingtalk because of: token is not exist\"));\n    }\n    \n    @Test\n    void assertHandleExceptionWithUrlIsNotFound() {\n        DingtalkJobErrorHandler actual = getDingtalkJobErrorHandler(createConfigurationProperties(\"http://localhost:\" + PORT + \"/404\"));\n        Throwable cause = new RuntimeException(\"test\");\n        actual.handleException(\"test_job\", cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.ERROR));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job' but failed to send dingtalk because of: unexpected http response status: 404\"));\n    }\n    \n    @Test\n    void assertHandleExceptionWithWrongUrl() {\n        DingtalkJobErrorHandler actual = getDingtalkJobErrorHandler(createNoSignJobConfigurationProperties(\"http://wrongUrl\"));\n        Throwable cause = new RuntimeException(\"test\");\n        actual.handleException(\"test_job\", cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.ERROR));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job', but failed to send dingtalk because of\"));\n    }\n    \n    @Test\n    void assertHandleExceptionWithNoSign() {\n        DingtalkJobErrorHandler actual = getDingtalkJobErrorHandler(createNoSignJobConfigurationProperties(\"http://localhost:\" + PORT + \"/send?access_token=mocked_token\"));\n        Throwable cause = new RuntimeException(\"test\");\n        actual.handleException(\"test_job\", cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.INFO));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job', an dingtalk message been sent successful.\"));\n    }\n    \n    private DingtalkJobErrorHandler getDingtalkJobErrorHandler(final Properties props) {\n        return (DingtalkJobErrorHandler) TypedSPILoader.getService(JobErrorHandler.class, \"DINGTALK\", props);\n    }\n    \n    private Properties createConfigurationProperties(final String webhook) {\n        Properties result = new Properties();\n        result.setProperty(DingtalkPropertiesConstants.WEBHOOK, webhook);\n        result.setProperty(DingtalkPropertiesConstants.KEYWORD, \"mocked_keyword\");\n        result.setProperty(DingtalkPropertiesConstants.SECRET, \"mocked_secret\");\n        result.setProperty(DingtalkPropertiesConstants.CONNECT_TIMEOUT_MILLISECONDS, \"4000\");\n        result.setProperty(DingtalkPropertiesConstants.READ_TIMEOUT_MILLISECONDS, \"6000\");\n        return result;\n    }\n    \n    private Properties createNoSignJobConfigurationProperties(final String webhook) {\n        Properties result = new Properties();\n        result.setProperty(DingtalkPropertiesConstants.WEBHOOK, webhook);\n        result.setProperty(DingtalkPropertiesConstants.KEYWORD, \"mocked_keyword\");\n        result.setProperty(DingtalkPropertiesConstants.CONNECT_TIMEOUT_MILLISECONDS, \"4000\");\n        result.setProperty(DingtalkPropertiesConstants.READ_TIMEOUT_MILLISECONDS, \"6000\");\n        return result;\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/dingtalk/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/dingtalk/fixture/DingtalkInternalController.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.dingtalk.fixture;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport com.google.common.collect.ImmutableMap;\nimport lombok.SneakyThrows;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.json.GsonFactory;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulController;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Mapping;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Param;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.ParamSource;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.RequestBody;\n\nimport javax.crypto.Mac;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.nio.charset.StandardCharsets;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Base64;\nimport java.util.Map;\n\npublic final class DingtalkInternalController implements RestfulController {\n    \n    private static final String ACCESS_TOKEN = \"mocked_token\";\n    \n    private static final String KEYWORD = \"mocked_keyword\";\n    \n    private static final String SECRET = \"mocked_secret\";\n    \n    /**\n     * Send Dingtalk message.\n     *\n     * @param accessToken access token\n     * @param timestamp timestamp\n     * @param sign sign\n     * @param body body\n     * @return send result\n     */\n    @Mapping(method = Http.POST, path = \"/send\")\n    public String send(@Param(name = \"access_token\", source = ParamSource.QUERY) final String accessToken,\n                       @Param(name = \"timestamp\", source = ParamSource.QUERY, required = false) final Long timestamp,\n                       @Param(name = \"sign\", source = ParamSource.QUERY, required = false) final String sign,\n                       @RequestBody final Map<String, Object> body) {\n        if (!ACCESS_TOKEN.equals(accessToken)) {\n            return GsonFactory.getGson().toJson(ImmutableMap.of(\"errcode\", 300001, \"errmsg\", \"token is not exist\"));\n        }\n        String content = ((Map) body.get(\"text\")).get(\"content\").toString();\n        if (!content.startsWith(KEYWORD)) {\n            return GsonFactory.getGson().toJson(ImmutableMap.of(\"errcode\", 310000, \"errmsg\", \"keywords not in content, more: [https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq]\"));\n        }\n        if (!Strings.isNullOrEmpty(sign)) {\n            Preconditions.checkNotNull(timestamp);\n            String checkSign = sign(timestamp);\n            if (!sign.equals(checkSign)) {\n                return GsonFactory.getGson().toJson(ImmutableMap.of(\"errcode\", 310000, \"errmsg\", \"sign not match, more: [https://ding-doc.dingtalk.com/doc#/serverapi2/qf2nxq]\"));\n            }\n        }\n        return GsonFactory.getGson().toJson(ImmutableMap.of(\"errcode\", 0, \"errmsg\", \"ok\"));\n    }\n    \n    @SneakyThrows({NoSuchAlgorithmException.class, InvalidKeyException.class})\n    private String sign(final Long timestamp) {\n        String stringToSign = timestamp + \"\\n\" + SECRET;\n        Mac mac = Mac.getInstance(\"HmacSHA256\");\n        mac.init(new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), \"HmacSHA256\"));\n        byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));\n        return new String(Base64.getEncoder().encode(signData), StandardCharsets.UTF_8);\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/dingtalk/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    <appender name=\"DingtalkJobErrorHandlerTestAppender\" class=\"ch.qos.logback.core.read.ListAppender\" />\n    <logger name=\"org.apache.shardingsphere.elasticjob.error.handler.dingtalk.DingtalkJobErrorHandler\" level=\"info\" additivity=\"false\">\n        <appender-ref ref=\"DingtalkJobErrorHandlerTestAppender\" />\n    </logger>\n</configuration>\n"
  },
  {
    "path": "ecosystem/error-handler/email/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-error-handler</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-error-handler-email</artifactId>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-test-util</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>com.sun.mail</groupId>\n            <artifactId>javax.mail</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "ecosystem/error-handler/email/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/email/EmailJobErrorHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.email;\n\nimport com.google.common.base.Strings;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\n\nimport javax.mail.Authenticator;\nimport javax.mail.BodyPart;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.PasswordAuthentication;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeBodyPart;\nimport javax.mail.internet.MimeMessage;\nimport javax.mail.internet.MimeMultipart;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Date;\nimport java.util.Properties;\n\n/**\n * Job error handler for send error message via email.\n */\n@Slf4j\npublic final class EmailJobErrorHandler implements JobErrorHandler {\n    \n    private Session session;\n    \n    private String subject;\n    \n    private String from;\n    \n    private String to;\n    \n    private String cc;\n    \n    private String bcc;\n    \n    @Override\n    public void init(final Properties props) {\n        String host = props.getProperty(EmailPropertiesConstants.HOST);\n        int port = Integer.parseInt(props.getProperty(EmailPropertiesConstants.PORT));\n        boolean isUseSSL = Boolean.parseBoolean(props.getProperty(EmailPropertiesConstants.IS_USE_SSL, EmailPropertiesConstants.DEFAULT_IS_USE_SSL));\n        boolean isDebug = Boolean.parseBoolean(props.getProperty(EmailPropertiesConstants.IS_DEBUG, EmailPropertiesConstants.DEFAULT_IS_DEBUG));\n        String username = props.getProperty(EmailPropertiesConstants.USERNAME);\n        String password = props.getProperty(EmailPropertiesConstants.PASSWORD);\n        String sslTrust = props.getProperty(EmailPropertiesConstants.SSL_TRUST);\n        session = Session.getDefaultInstance(createSessionProperties(host, port, isUseSSL, isDebug, sslTrust), getSessionAuthenticator(username, password));\n        subject = props.getProperty(EmailPropertiesConstants.SUBJECT, EmailPropertiesConstants.DEFAULT_SUBJECT);\n        from = props.getProperty(EmailPropertiesConstants.FROM);\n        to = props.getProperty(EmailPropertiesConstants.TO);\n        cc = props.getProperty(EmailPropertiesConstants.CC);\n        bcc = props.getProperty(EmailPropertiesConstants.BCC);\n    }\n    \n    private Properties createSessionProperties(final String host, final int port, final boolean isUseSSL, final boolean isDebug, final String sslTrust) {\n        Properties result = new Properties();\n        result.put(\"mail.smtp.host\", host);\n        result.put(\"mail.smtp.port\", port);\n        result.put(\"mail.smtp.auth\", Boolean.TRUE.toString());\n        result.put(\"mail.transport.protocol\", \"smtp\");\n        result.setProperty(\"mail.debug\", Boolean.toString(isDebug));\n        if (isUseSSL) {\n            result.setProperty(\"mail.smtp.socketFactory.class\", \"javax.net.ssl.SSLSocketFactory\");\n            result.setProperty(\"mail.smtp.socketFactory.fallback\", Boolean.FALSE.toString());\n            if (!Strings.isNullOrEmpty(sslTrust)) {\n                result.setProperty(\"mail.smtp.ssl.trust\", sslTrust);\n            }\n        }\n        return result;\n    }\n    \n    private Authenticator getSessionAuthenticator(final String username, final String password) {\n        return new Authenticator() {\n            \n            @Override\n            public PasswordAuthentication getPasswordAuthentication() {\n                return new PasswordAuthentication(username, password);\n            }\n        };\n    }\n    \n    @Override\n    public void handleException(final String jobName, final Throwable cause) {\n        String errorMessage = getErrorMessage(jobName, cause);\n        try {\n            sendMessage(createMessage(errorMessage));\n            log.info(\"An exception has occurred in Job '{}', an email has been sent successfully.\", jobName, cause);\n        } catch (final MessagingException ex) {\n            cause.addSuppressed(ex);\n            log.error(\"An exception has occurred in Job '{}' but failed to send email because of\", jobName, cause);\n        }\n    }\n    \n    private String getErrorMessage(final String jobName, final Throwable cause) {\n        StringWriter writer = new StringWriter();\n        cause.printStackTrace(new PrintWriter(writer, true));\n        return String.format(\"Job '%s' exception occur in job processing, caused by %s\", jobName, writer);\n    }\n    \n    private Message createMessage(final String content) throws MessagingException {\n        MimeMessage result = new MimeMessage(session);\n        result.setFrom(new InternetAddress(from));\n        result.setSubject(subject);\n        result.setSentDate(new Date());\n        Multipart multipart = new MimeMultipart();\n        BodyPart mailBody = new MimeBodyPart();\n        mailBody.setContent(content, \"text/html; charset=utf-8\");\n        multipart.addBodyPart(mailBody);\n        result.setContent(multipart);\n        if (StringUtils.isNotBlank(to)) {\n            String[] tos = to.split(\",\");\n            for (String each : tos) {\n                result.addRecipient(Message.RecipientType.TO, new InternetAddress(each));\n            }\n        }\n        if (!Strings.isNullOrEmpty(cc)) {\n            result.addRecipient(Message.RecipientType.CC, new InternetAddress(cc));\n        }\n        if (!Strings.isNullOrEmpty(bcc)) {\n            result.addRecipient(Message.RecipientType.BCC, new InternetAddress(bcc));\n        }\n        result.saveChanges();\n        return result;\n    }\n    \n    private void sendMessage(final Message message) throws MessagingException {\n        try (Transport transport = session.getTransport()) {\n            transport.connect();\n            transport.sendMessage(message, message.getAllRecipients());\n        }\n    }\n    \n    @Override\n    public String getType() {\n        return \"EMAIL\";\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/email/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/email/EmailJobErrorHandlerPropertiesValidator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.email;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.PropertiesPreconditions;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandlerPropertiesValidator;\n\nimport java.util.Properties;\n\n/**\n * Job error handler properties validator for email.\n */\npublic final class EmailJobErrorHandlerPropertiesValidator implements JobErrorHandlerPropertiesValidator {\n    \n    @Override\n    public void validate(final Properties props) {\n        PropertiesPreconditions.checkRequired(props, EmailPropertiesConstants.HOST);\n        PropertiesPreconditions.checkRequired(props, EmailPropertiesConstants.PORT);\n        PropertiesPreconditions.checkPositiveInteger(props, EmailPropertiesConstants.PORT);\n        PropertiesPreconditions.checkRequired(props, EmailPropertiesConstants.USERNAME);\n        PropertiesPreconditions.checkRequired(props, EmailPropertiesConstants.PASSWORD);\n        PropertiesPreconditions.checkRequired(props, EmailPropertiesConstants.FROM);\n        PropertiesPreconditions.checkRequired(props, EmailPropertiesConstants.TO);\n    }\n    \n    @Override\n    public String getType() {\n        return \"EMAIL\";\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/email/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/email/EmailPropertiesConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.email;\n\n/**\n * Job error handler properties constants for send error message via email.\n */\npublic final class EmailPropertiesConstants {\n    \n    public static final String DEFAULT_IS_USE_SSL = Boolean.TRUE.toString();\n    \n    public static final String DEFAULT_SUBJECT = \"ElasticJob error message\";\n    \n    public static final String DEFAULT_IS_DEBUG = Boolean.FALSE.toString();\n    \n    private static final String PREFIX = \"email.\";\n    \n    public static final String HOST = PREFIX + \"host\";\n    \n    public static final String SSL_TRUST = PREFIX + \"ssl.trust\";\n    \n    public static final String PORT = PREFIX + \"port\";\n    \n    public static final String USERNAME = PREFIX + \"username\";\n    \n    public static final String PASSWORD = PREFIX + \"password\";\n    \n    public static final String IS_USE_SSL = PREFIX + \"useSsl\";\n    \n    public static final String SUBJECT = PREFIX + \"subject\";\n    \n    public static final String FROM = PREFIX + \"from\";\n    \n    public static final String TO = PREFIX + \"to\";\n    \n    public static final String CC = PREFIX + \"cc\";\n    \n    public static final String BCC = PREFIX + \"bcc\";\n    \n    public static final String IS_DEBUG = PREFIX + \"debug\";\n}\n"
  },
  {
    "path": "ecosystem/error-handler/email/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.error.handler.email.EmailJobErrorHandler\n"
  },
  {
    "path": "ecosystem/error-handler/email/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandlerPropertiesValidator",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.error.handler.email.EmailJobErrorHandlerPropertiesValidator\n"
  },
  {
    "path": "ecosystem/error-handler/email/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/email/EmailJobErrorHandlerPropertiesValidatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.email;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandlerPropertiesValidator;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass EmailJobErrorHandlerPropertiesValidatorTest {\n    \n    @Test\n    void assertValidateWithNormal() {\n        Properties properties = new Properties();\n        properties.setProperty(EmailPropertiesConstants.HOST, \"host\");\n        properties.setProperty(EmailPropertiesConstants.SSL_TRUST, \"*\");\n        properties.setProperty(EmailPropertiesConstants.PORT, \"465\");\n        properties.setProperty(EmailPropertiesConstants.USERNAME, \"username\");\n        properties.setProperty(EmailPropertiesConstants.PASSWORD, \"password\");\n        properties.setProperty(EmailPropertiesConstants.FROM, \"from@xxx.xx\");\n        properties.setProperty(EmailPropertiesConstants.TO, \"to@xxx.xx\");\n        TypedSPILoader.getService(JobErrorHandlerPropertiesValidator.class, \"EMAIL\").validate(properties);\n    }\n    \n    @Test\n    void assertValidateWithPropsIsNull() {\n        assertThrows(NullPointerException.class, () -> TypedSPILoader.getService(JobErrorHandlerPropertiesValidator.class, \"EMAIL\").validate(null));\n    }\n    \n    @Test\n    void assertValidateWithHostIsNull() {\n        try {\n            TypedSPILoader.getService(JobErrorHandlerPropertiesValidator.class, \"EMAIL\").validate(new Properties());\n        } catch (final IllegalArgumentException ex) {\n            assertThat(ex.getMessage(), is(String.format(\"The property `%s` is required.\", EmailPropertiesConstants.HOST)));\n        }\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/email/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/email/EmailJobErrorHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.email;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.core.read.ListAppender;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport org.slf4j.LoggerFactory;\n\nimport javax.mail.Address;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Session;\nimport javax.mail.Transport;\nimport java.util.List;\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass EmailJobErrorHandlerTest {\n    \n    private static List<LoggingEvent> appenderList;\n    \n    @Mock\n    private Session session;\n    \n    @Mock\n    private Transport transport;\n    \n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    @BeforeAll\n    static void init() {\n        ch.qos.logback.classic.Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(EmailJobErrorHandler.class);\n        ListAppender<LoggingEvent> appender = (ListAppender) log.getAppender(\"EmailJobErrorHandlerTestAppender\");\n        appenderList = appender.list;\n    }\n    \n    @BeforeEach\n    void setUp() {\n        appenderList.clear();\n    }\n    \n    @Test\n    void assertHandleExceptionWithMessagingException() {\n        EmailJobErrorHandler emailJobErrorHandler = getEmailJobErrorHandler(createConfigurationProperties());\n        Throwable cause = new RuntimeException(\"test\");\n        String jobName = \"test_job\";\n        emailJobErrorHandler.handleException(jobName, cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.ERROR));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job' but failed to send email because of\"));\n    }\n    \n    @Test\n    void assertHandleExceptionSucceedInSendingEmail() throws MessagingException {\n        EmailJobErrorHandler emailJobErrorHandler = getEmailJobErrorHandler(createConfigurationProperties());\n        setUpMockSession(session);\n        ReflectionUtils.setFieldValue(emailJobErrorHandler, \"session\", session);\n        Throwable cause = new RuntimeException(\"test\");\n        String jobName = \"test_job\";\n        when(session.getTransport()).thenReturn(transport);\n        emailJobErrorHandler.handleException(jobName, cause);\n        verify(transport).sendMessage(any(Message.class), any(Address[].class));\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.INFO));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job', an email has been sent successfully.\"));\n    }\n    \n    private EmailJobErrorHandler getEmailJobErrorHandler(final Properties props) {\n        return (EmailJobErrorHandler) TypedSPILoader.getService(JobErrorHandler.class, \"EMAIL\", props);\n    }\n    \n    private void setUpMockSession(final Session session) {\n        Properties props = new Properties();\n        ReflectionUtils.setFieldValue(session, \"props\", props);\n        when(session.getProperties()).thenReturn(props);\n    }\n    \n    private Properties createConfigurationProperties() {\n        Properties result = new Properties();\n        result.setProperty(EmailPropertiesConstants.HOST, \"localhost\");\n        result.setProperty(EmailPropertiesConstants.SSL_TRUST, \"*\");\n        result.setProperty(EmailPropertiesConstants.PORT, \"465\");\n        result.setProperty(EmailPropertiesConstants.USERNAME, \"user\");\n        result.setProperty(EmailPropertiesConstants.PASSWORD, \"xxx\");\n        result.setProperty(EmailPropertiesConstants.SUBJECT, \"Unit test notification\");\n        result.setProperty(EmailPropertiesConstants.FROM, \"from@xxx.xx\");\n        result.setProperty(EmailPropertiesConstants.TO, \"to1@xxx.xx,to2@xxx.xx\");\n        result.setProperty(EmailPropertiesConstants.CC, \"cc@xxx.xx\");\n        result.setProperty(EmailPropertiesConstants.BCC, \"bcc@xxx.xx\");\n        return result;\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/email/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    <appender name=\"EmailJobErrorHandlerTestAppender\" class=\"ch.qos.logback.core.read.ListAppender\" />\n    <logger name=\"org.apache.shardingsphere.elasticjob.error.handler.email.EmailJobErrorHandler\" level=\"info\" additivity=\"false\">\n        <appender-ref ref=\"EmailJobErrorHandlerTestAppender\" />\n    </logger>\n</configuration>\n"
  },
  {
    "path": "ecosystem/error-handler/normal/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-error-handler</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-error-handler-normal</artifactId>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "ecosystem/error-handler/normal/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/normal/IgnoreJobErrorHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.normal;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\n\n/**\n * Job error handler for ignore exception.\n */\npublic final class IgnoreJobErrorHandler implements JobErrorHandler {\n    \n    @Override\n    public void handleException(final String jobName, final Throwable cause) {\n    }\n    \n    @Override\n    public String getType() {\n        return \"IGNORE\";\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/normal/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/normal/LogJobErrorHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.normal;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\n\n/**\n * Job error handler for log error message.\n */\n@Slf4j\npublic final class LogJobErrorHandler implements JobErrorHandler {\n    \n    @Override\n    public void handleException(final String jobName, final Throwable cause) {\n        log.error(String.format(\"Job '%s' exception occur in job processing\", jobName), cause);\n    }\n    \n    @Override\n    public String getType() {\n        return \"LOG\";\n    }\n    \n    @Override\n    public boolean isDefault() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/normal/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/normal/ThrowJobErrorHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.normal;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\n\n/**\n * Job error handler for throw exception.\n */\npublic final class ThrowJobErrorHandler implements JobErrorHandler {\n    \n    @Override\n    public void handleException(final String jobName, final Throwable cause) {\n        throw new JobSystemException(cause);\n    }\n    \n    @Override\n    public String getType() {\n        return \"THROW\";\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/normal/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.error.handler.normal.LogJobErrorHandler\norg.apache.shardingsphere.elasticjob.error.handler.normal.IgnoreJobErrorHandler\norg.apache.shardingsphere.elasticjob.error.handler.normal.ThrowJobErrorHandler\n"
  },
  {
    "path": "ecosystem/error-handler/normal/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/normal/IgnoreJobErrorHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.normal;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Properties;\n\nclass IgnoreJobErrorHandlerTest {\n    \n    @Test\n    void assertHandleException() {\n        TypedSPILoader.getService(JobErrorHandler.class, \"IGNORE\", new Properties()).handleException(\"test_job\", new RuntimeException(\"test\"));\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/normal/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/normal/LogJobErrorHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.normal;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.core.read.ListAppender;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.List;\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass LogJobErrorHandlerTest {\n    \n    private static List<LoggingEvent> appenderList;\n    \n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    @BeforeAll\n    static void setupLogger() {\n        ch.qos.logback.classic.Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(LogJobErrorHandler.class);\n        ListAppender<LoggingEvent> appender = (ListAppender) log.getAppender(\"LogJobErrorHandlerTestAppender\");\n        appenderList = appender.list;\n    }\n    \n    @BeforeEach\n    void setUp() {\n        appenderList.clear();\n    }\n    \n    @Test\n    void assertHandleException() {\n        LogJobErrorHandler actual = (LogJobErrorHandler) TypedSPILoader.getService(JobErrorHandler.class, \"LOG\", new Properties());\n        Throwable cause = new RuntimeException(\"test\");\n        actual.handleException(\"test_job\", cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.ERROR));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"Job 'test_job' exception occur in job processing\"));\n        actual.close();\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/normal/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/normal/ThrowJobErrorHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.normal;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Properties;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass ThrowJobErrorHandlerTest {\n    \n    @Test\n    void assertHandleException() {\n        assertThrows(JobSystemException.class, () -> TypedSPILoader.getService(JobErrorHandler.class, \"THROW\", new Properties()).handleException(\"test_job\", new RuntimeException(\"test\")));\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/normal/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n            <level>ERROR</level>\n        </filter>\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    <appender name=\"LogJobErrorHandlerTestAppender\" class=\"ch.qos.logback.core.read.ListAppender\" />\n    \n    <root>\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.shardingsphere.elasticjob.error.handler.normal.LogJobErrorHandler\" level=\"error\" additivity=\"false\">\n        <appender-ref ref=\"LogJobErrorHandlerTestAppender\" />\n    </logger>\n</configuration>\n"
  },
  {
    "path": "ecosystem/error-handler/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-ecosystem</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-error-handler</artifactId>\n    <packaging>pom</packaging>\n    \n    <modules>\n        <module>normal</module>\n        <module>email</module>\n        <module>wechat</module>\n        <module>dingtalk</module>\n    </modules>\n</project>\n"
  },
  {
    "path": "ecosystem/error-handler/wechat/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-error-handler</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-error-handler-wechat</artifactId>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-restful</artifactId>\n            <version>${project.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpclient</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpcore</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "ecosystem/error-handler/wechat/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/wechat/WechatJobErrorHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.wechat;\n\nimport com.google.common.collect.ImmutableMap;\nimport com.google.gson.JsonObject;\nimport lombok.SneakyThrows;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.util.EntityUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.json.GsonFactory;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.net.HttpURLConnection;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.Properties;\n\n/**\n * Job error handler for send error message via wechat.\n */\n@Slf4j\npublic final class WechatJobErrorHandler implements JobErrorHandler {\n    \n    private final CloseableHttpClient httpclient = HttpClients.createDefault();\n    \n    private String webhook;\n    \n    private int connectTimeoutMilliseconds;\n    \n    private int readTimeoutMilliseconds;\n    \n    @Override\n    public void init(final Properties props) {\n        webhook = props.getProperty(WechatPropertiesConstants.WEBHOOK);\n        connectTimeoutMilliseconds = Integer.parseInt(props.getProperty(WechatPropertiesConstants.CONNECT_TIMEOUT_MILLISECONDS, WechatPropertiesConstants.DEFAULT_CONNECT_TIMEOUT_MILLISECONDS));\n        readTimeoutMilliseconds = Integer.parseInt(props.getProperty(WechatPropertiesConstants.READ_TIMEOUT_MILLISECONDS, WechatPropertiesConstants.DEFAULT_READ_TIMEOUT_MILLISECONDS));\n    }\n    \n    @Override\n    public void handleException(final String jobName, final Throwable cause) {\n        HttpPost httpPost = createHTTPPostMethod(jobName, cause);\n        try (CloseableHttpResponse response = httpclient.execute(httpPost)) {\n            int status = response.getStatusLine().getStatusCode();\n            if (HttpURLConnection.HTTP_OK == status) {\n                JsonObject resp = GsonFactory.getGson().fromJson(EntityUtils.toString(response.getEntity()), JsonObject.class);\n                if (!\"0\".equals(resp.get(\"errcode\").getAsString())) {\n                    log.error(\"An exception has occurred in Job '{}' but failed to send wechat because of: {}\", jobName, resp.get(\"errmsg\").getAsString(), cause);\n                } else {\n                    log.info(\"An exception has occurred in Job '{}', an wechat message has been sent successful.\", jobName, cause);\n                }\n            } else {\n                log.error(\"An exception has occurred in Job '{}' but failed to send wechat because of: unexpected http response status: {}\", jobName, status, cause);\n            }\n        } catch (final IOException ex) {\n            cause.addSuppressed(ex);\n            log.error(\"An exception has occurred in Job '{}' but failed to send wechat because of\", jobName, cause);\n        }\n    }\n    \n    private HttpPost createHTTPPostMethod(final String jobName, final Throwable cause) {\n        HttpPost result = new HttpPost(webhook);\n        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeoutMilliseconds).setSocketTimeout(readTimeoutMilliseconds).build();\n        result.setConfig(requestConfig);\n        StringEntity entity = new StringEntity(getJsonParameter(getErrorMessage(jobName, cause)), StandardCharsets.UTF_8);\n        entity.setContentEncoding(StandardCharsets.UTF_8.name());\n        entity.setContentType(\"application/json\");\n        result.setEntity(entity);\n        return result;\n    }\n    \n    private String getJsonParameter(final String message) {\n        return GsonFactory.getGson().toJson(ImmutableMap.of(\"msgtype\", \"text\", \"text\", Collections.singletonMap(\"content\", message)));\n    }\n    \n    private String getErrorMessage(final String jobName, final Throwable cause) {\n        StringWriter stringWriter = new StringWriter();\n        cause.printStackTrace(new PrintWriter(stringWriter, true));\n        return String.format(\"Job '%s' exception occur in job processing, caused by %s\", jobName, stringWriter);\n    }\n    \n    @Override\n    public String getType() {\n        return \"WECHAT\";\n    }\n    \n    @SneakyThrows(IOException.class)\n    @Override\n    public void close() {\n        httpclient.close();\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/wechat/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/wechat/WechatJobErrorHandlerPropertiesValidator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.wechat;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.PropertiesPreconditions;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandlerPropertiesValidator;\n\nimport java.util.Properties;\n\n/**\n * Job error handler properties validator for wechat.\n */\npublic final class WechatJobErrorHandlerPropertiesValidator implements JobErrorHandlerPropertiesValidator {\n    \n    @Override\n    public void validate(final Properties props) {\n        PropertiesPreconditions.checkRequired(props, WechatPropertiesConstants.WEBHOOK);\n        PropertiesPreconditions.checkPositiveInteger(props, WechatPropertiesConstants.CONNECT_TIMEOUT_MILLISECONDS);\n        PropertiesPreconditions.checkPositiveInteger(props, WechatPropertiesConstants.READ_TIMEOUT_MILLISECONDS);\n    }\n    \n    @Override\n    public String getType() {\n        return \"WECHAT\";\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/wechat/src/main/java/org/apache/shardingsphere/elasticjob/error/handler/wechat/WechatPropertiesConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.wechat;\n\n/**\n * Job error handler properties constants for send error message via wechat.\n */\npublic final class WechatPropertiesConstants {\n    \n    public static final String DEFAULT_CONNECT_TIMEOUT_MILLISECONDS = \"3000\";\n    \n    public static final String DEFAULT_READ_TIMEOUT_MILLISECONDS = \"5000\";\n    \n    private static final String PREFIX = \"wechat.\";\n    \n    public static final String WEBHOOK = PREFIX + \"webhook\";\n    \n    public static final String CONNECT_TIMEOUT_MILLISECONDS = PREFIX + \"connectTimeoutMilliseconds\";\n    \n    public static final String READ_TIMEOUT_MILLISECONDS = PREFIX + \"readTimeoutMilliseconds\";\n}\n"
  },
  {
    "path": "ecosystem/error-handler/wechat/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.error.handler.wechat.WechatJobErrorHandler\n"
  },
  {
    "path": "ecosystem/error-handler/wechat/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandlerPropertiesValidator",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.error.handler.wechat.WechatJobErrorHandlerPropertiesValidator\n"
  },
  {
    "path": "ecosystem/error-handler/wechat/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/wechat/WechatJobErrorHandlerPropertiesValidatorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.wechat;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandlerPropertiesValidator;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass WechatJobErrorHandlerPropertiesValidatorTest {\n    \n    @Test\n    void assertValidateWithNormal() {\n        Properties properties = new Properties();\n        properties.setProperty(WechatPropertiesConstants.WEBHOOK, \"webhook\");\n        properties.setProperty(WechatPropertiesConstants.READ_TIMEOUT_MILLISECONDS, \"1000\");\n        properties.setProperty(WechatPropertiesConstants.CONNECT_TIMEOUT_MILLISECONDS, \"2000\");\n        TypedSPILoader.getService(JobErrorHandlerPropertiesValidator.class, \"WECHAT\").validate(properties);\n    }\n    \n    @Test\n    void assertValidateWithPropsIsNull() {\n        assertThrows(NullPointerException.class, () -> TypedSPILoader.getService(JobErrorHandlerPropertiesValidator.class, \"WECHAT\").validate(null));\n    }\n    \n    @Test\n    void assertValidateWithWebhookIsNull() {\n        try {\n            TypedSPILoader.getService(JobErrorHandlerPropertiesValidator.class, \"WECHAT\").validate(new Properties());\n        } catch (final IllegalArgumentException ex) {\n            assertThat(ex.getMessage(), is(String.format(\"The property `%s` is required.\", WechatPropertiesConstants.WEBHOOK)));\n        }\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/wechat/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/wechat/WechatJobErrorHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.wechat;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.core.read.ListAppender;\nimport org.apache.curator.test.InstanceSpec;\nimport org.apache.shardingsphere.elasticjob.error.handler.wechat.fixture.WechatInternalController;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulService;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulServiceConfiguration;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulService;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.List;\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass WechatJobErrorHandlerTest {\n    \n    private static final int PORT = InstanceSpec.getRandomPort();\n    \n    private static final String HOST = \"localhost\";\n    \n    private static RestfulService restfulService;\n    \n    private static List<LoggingEvent> appenderList;\n    \n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    @BeforeAll\n    static void init() {\n        NettyRestfulServiceConfiguration config = new NettyRestfulServiceConfiguration(PORT);\n        config.setHost(HOST);\n        config.addControllerInstances(new WechatInternalController());\n        restfulService = new NettyRestfulService(config);\n        restfulService.startup();\n        ch.qos.logback.classic.Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(WechatJobErrorHandler.class);\n        ListAppender<LoggingEvent> appender = (ListAppender) log.getAppender(\"WechatJobErrorHandlerTestAppender\");\n        appenderList = appender.list;\n    }\n    \n    @BeforeEach\n    void setUp() {\n        appenderList.clear();\n    }\n    \n    @AfterAll\n    static void close() {\n        if (null != restfulService) {\n            restfulService.shutdown();\n        }\n    }\n    \n    @Test\n    void assertHandleExceptionWithNotifySuccessful() {\n        WechatJobErrorHandler actual = getWechatJobErrorHandler(createConfigurationProperties(\"http://localhost:\" + PORT + \"/send?key=mocked_key\"));\n        Throwable cause = new RuntimeException(\"test\");\n        actual.handleException(\"test_job\", cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.INFO));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job', an wechat message has been sent successful.\"));\n    }\n    \n    @Test\n    void assertHandleExceptionWithWrongToken() {\n        WechatJobErrorHandler actual = getWechatJobErrorHandler(createConfigurationProperties(\"http://localhost:\" + PORT + \"/send?key=wrong_key\"));\n        Throwable cause = new RuntimeException(\"test\");\n        actual.handleException(\"test_job\", cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.ERROR));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job' but failed to send wechat because of: token is invalid\"));\n    }\n    \n    @Test\n    void assertHandleExceptionWithWrongUrl() {\n        WechatJobErrorHandler actual = getWechatJobErrorHandler(createConfigurationProperties(\"http://wrongUrl\"));\n        Throwable cause = new RuntimeException(\"test\");\n        actual.handleException(\"test_job\", cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.ERROR));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job' but failed to send wechat because of\"));\n    }\n    \n    @Test\n    void assertHandleExceptionWithUrlIsNotFound() {\n        WechatJobErrorHandler actual = getWechatJobErrorHandler(createConfigurationProperties(\"http://localhost:\" + PORT + \"/404\"));\n        Throwable cause = new RuntimeException(\"test\");\n        actual.handleException(\"test_job\", cause);\n        assertThat(appenderList.size(), is(1));\n        assertThat(appenderList.get(0).getLevel(), is(Level.ERROR));\n        assertThat(appenderList.get(0).getFormattedMessage(), is(\"An exception has occurred in Job 'test_job' but failed to send wechat because of: unexpected http response status: 404\"));\n    }\n    \n    private WechatJobErrorHandler getWechatJobErrorHandler(final Properties props) {\n        return (WechatJobErrorHandler) TypedSPILoader.getService(JobErrorHandler.class, \"WECHAT\", props);\n    }\n    \n    private Properties createConfigurationProperties(final String webhook) {\n        Properties result = new Properties();\n        result.setProperty(WechatPropertiesConstants.WEBHOOK, webhook);\n        result.setProperty(WechatPropertiesConstants.CONNECT_TIMEOUT_MILLISECONDS, \"1000\");\n        result.setProperty(WechatPropertiesConstants.READ_TIMEOUT_MILLISECONDS, \"2000\");\n        return result;\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/wechat/src/test/java/org/apache/shardingsphere/elasticjob/error/handler/wechat/fixture/WechatInternalController.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.error.handler.wechat.fixture;\n\nimport com.google.common.collect.ImmutableMap;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.json.GsonFactory;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulController;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Mapping;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Param;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.ParamSource;\n\npublic final class WechatInternalController implements RestfulController {\n    \n    private static final String KEY = \"mocked_key\";\n    \n    /**\n     * Send Wechat message.\n     *\n     * @param key access token\n     * @return send result\n     */\n    @Mapping(method = Http.POST, path = \"/send\")\n    public String send(@Param(name = \"key\", source = ParamSource.QUERY) final String key) {\n        if (!KEY.equals(key)) {\n            return GsonFactory.getGson().toJson(ImmutableMap.of(\"errcode\", 1, \"errmsg\", \"token is invalid\"));\n        }\n        return GsonFactory.getGson().toJson(ImmutableMap.of(\"errcode\", 0, \"errmsg\", \"ok\"));\n    }\n}\n"
  },
  {
    "path": "ecosystem/error-handler/wechat/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    <appender name=\"WechatJobErrorHandlerTestAppender\" class=\"ch.qos.logback.core.read.ListAppender\" />\n    <logger name=\"org.apache.shardingsphere.elasticjob.error.handler.wechat.WechatJobErrorHandler\" level=\"info\" additivity=\"false\">\n        <appender-ref ref=\"WechatJobErrorHandlerTestAppender\" />\n    </logger>\n</configuration>\n"
  },
  {
    "path": "ecosystem/executor/dataflow/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-executor</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-dataflow-executor</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "ecosystem/executor/dataflow/src/main/java/org/apache/shardingsphere/elasticjob/dataflow/executor/DataflowJobExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.dataflow.executor;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob;\nimport org.apache.shardingsphere.elasticjob.dataflow.props.DataflowJobProperties;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor;\n\nimport java.util.List;\n\n/**\n * Dataflow job executor.\n */\npublic final class DataflowJobExecutor implements ClassedJobItemExecutor<DataflowJob> {\n    \n    @Override\n    public void process(final DataflowJob elasticJob, final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService, final ShardingContext shardingContext) {\n        if (Boolean.parseBoolean(jobConfig.getProps().getOrDefault(DataflowJobProperties.STREAM_PROCESS_KEY, false).toString())) {\n            streamingExecute(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n        } else {\n            oneOffExecute(elasticJob, shardingContext);\n        }\n    }\n    \n    private void streamingExecute(final DataflowJob elasticJob, final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService, final ShardingContext shardingContext) {\n        List<Object> data = fetchData(elasticJob, shardingContext);\n        while (null != data && !data.isEmpty()) {\n            processData(elasticJob, shardingContext, data);\n            if (!isEligibleForJobRunning(jobConfig, jobRuntimeService)) {\n                break;\n            }\n            data = fetchData(elasticJob, shardingContext);\n        }\n    }\n    \n    private boolean isEligibleForJobRunning(final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService) {\n        return !jobRuntimeService.isNeedSharding() && Boolean.parseBoolean(jobConfig.getProps().getOrDefault(DataflowJobProperties.STREAM_PROCESS_KEY, false).toString());\n    }\n    \n    private void oneOffExecute(final DataflowJob elasticJob, final ShardingContext shardingContext) {\n        List<Object> data = fetchData(elasticJob, shardingContext);\n        if (null != data && !data.isEmpty()) {\n            processData(elasticJob, shardingContext, data);\n        }\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    private List<Object> fetchData(final DataflowJob elasticJob, final ShardingContext shardingContext) {\n        return elasticJob.fetchData(shardingContext);\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    private void processData(final DataflowJob elasticJob, final ShardingContext shardingContext, final List<Object> data) {\n        elasticJob.processData(shardingContext, data);\n    }\n    \n    @Override\n    public Class<DataflowJob> getElasticJobClass() {\n        return DataflowJob.class;\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/dataflow/src/main/java/org/apache/shardingsphere/elasticjob/dataflow/job/DataflowJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.dataflow.job;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\nimport java.util.List;\n\n/**\n * Dataflow job.\n * \n * @param <T> type of data\n */\npublic interface DataflowJob<T> extends ElasticJob {\n    \n    /**\n     * Fetch to be processed data.\n     *\n     * @param shardingContext sharding context\n     * @return to be processed data\n     */\n    List<T> fetchData(ShardingContext shardingContext);\n    \n    /**\n     * Process data.\n     *\n     * @param shardingContext sharding context\n     * @param data to be processed data\n     */\n    void processData(ShardingContext shardingContext, List<T> data);\n}\n"
  },
  {
    "path": "ecosystem/executor/dataflow/src/main/java/org/apache/shardingsphere/elasticjob/dataflow/props/DataflowJobProperties.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.dataflow.props;\n\n/**\n * Dataflow job properties.\n */\npublic final class DataflowJobProperties {\n    \n    /**\n     * Whether to use stream mode to process dataflow job.\n     */\n    public static final String STREAM_PROCESS_KEY = \"streaming.process\";\n}\n"
  },
  {
    "path": "ecosystem/executor/dataflow/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.dataflow.executor.DataflowJobExecutor\n"
  },
  {
    "path": "ecosystem/executor/dataflow/src/test/java/org/apache/shardingsphere/elasticjob/dataflow/executor/DataflowJobExecutorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.dataflow.executor;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob;\nimport org.apache.shardingsphere.elasticjob.dataflow.props.DataflowJobProperties;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass DataflowJobExecutorTest {\n    \n    private DataflowJobExecutor jobExecutor;\n    \n    @Mock\n    private DataflowJob elasticJob;\n    \n    @Mock\n    private JobConfiguration jobConfig;\n    \n    @Mock\n    private JobRuntimeService jobRuntimeService;\n    \n    @Mock\n    private ShardingContext shardingContext;\n    \n    @Mock\n    private Properties properties;\n    \n    @BeforeEach\n    void createJobExecutor() {\n        jobExecutor = new DataflowJobExecutor();\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void assertProcessWithStreamingExecute() {\n        List<String> data = Arrays.asList(\"DataflowJob1\", \"DataflowJob2\");\n        when(jobConfig.getProps()).thenReturn(properties);\n        when(properties.getOrDefault(DataflowJobProperties.STREAM_PROCESS_KEY, false)).thenReturn(\"true\");\n        when(elasticJob.fetchData(shardingContext)).thenReturn(data);\n        when(jobRuntimeService.isNeedSharding()).thenReturn(true);\n        jobExecutor.process(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n        verify(elasticJob, times(1)).processData(shardingContext, data);\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    @Test\n    void assertProcessWithOneOffExecute() {\n        List<String> data = Arrays.asList(\"DataflowJob1\", \"DataflowJob2\");\n        when(jobConfig.getProps()).thenReturn(properties);\n        when(properties.getOrDefault(DataflowJobProperties.STREAM_PROCESS_KEY, false)).thenReturn(\"false\");\n        when(elasticJob.fetchData(shardingContext)).thenReturn(data);\n        jobExecutor.process(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n        verify(elasticJob, times(1)).processData(shardingContext, data);\n    }\n    \n    @Test\n    void assertGetElasticJobClass() {\n        assertThat(jobExecutor.getElasticJobClass(), is(DataflowJob.class));\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/http/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-executor</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-http-executor</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-restful</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.awaitility</groupId>\n            <artifactId>awaitility</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "ecosystem/executor/http/src/main/java/org/apache/shardingsphere/elasticjob/http/executor/HttpJobExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.http.executor;\n\nimport com.google.common.base.Strings;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.http.pojo.HttpParam;\nimport org.apache.shardingsphere.elasticjob.http.props.HttpJobProperties;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionException;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.json.GsonFactory;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.TypedJobItemExecutor;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\n\n/**\n * Http job executor.\n */\n@Slf4j\npublic final class HttpJobExecutor implements TypedJobItemExecutor {\n    \n    @Override\n    public void process(final ElasticJob elasticJob, final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService, final ShardingContext shardingContext) {\n        HttpParam httpParam = new HttpParam(jobConfig.getProps());\n        HttpURLConnection connection = null;\n        try {\n            connection = getHttpURLConnection(httpParam, shardingContext);\n            connection.connect();\n            String data = httpParam.getData();\n            if (httpParam.isWriteMethod() && !Strings.isNullOrEmpty(data)) {\n                try (OutputStream outputStream = connection.getOutputStream()) {\n                    outputStream.write(data.getBytes(StandardCharsets.UTF_8));\n                }\n            }\n            int responseCode = connection.getResponseCode();\n            StringBuilder result = new StringBuilder();\n            try (\n                    InputStream inputStream = getConnectionInputStream(jobConfig.getJobName(), connection, responseCode);\n                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {\n                String line;\n                while (null != (line = bufferedReader.readLine())) {\n                    result.append(line);\n                }\n            }\n            if (isRequestSucceed(responseCode)) {\n                log.debug(\"HTTP job execute result : {}\", result);\n            } else {\n                log.warn(\"HTTP job {} executed with response body {}\", jobConfig.getJobName(), result);\n            }\n        } catch (final IOException ex) {\n            throw new JobExecutionException(ex);\n        } finally {\n            if (null != connection) {\n                connection.disconnect();\n            }\n        }\n    }\n    \n    private HttpURLConnection getHttpURLConnection(final HttpParam httpParam, final ShardingContext shardingContext) throws IOException {\n        URL url = new URL(httpParam.getUrl());\n        HttpURLConnection result = (HttpURLConnection) url.openConnection();\n        result.setRequestMethod(httpParam.getMethod());\n        result.setDoOutput(true);\n        result.setConnectTimeout(httpParam.getConnectTimeoutMilliseconds());\n        result.setReadTimeout(httpParam.getReadTimeoutMilliseconds());\n        if (!Strings.isNullOrEmpty(httpParam.getContentType())) {\n            result.setRequestProperty(\"Content-Type\", httpParam.getContentType());\n        }\n        result.setRequestProperty(HttpJobProperties.SHARDING_CONTEXT_KEY, GsonFactory.getGson().toJson(shardingContext));\n        return result;\n    }\n    \n    private InputStream getConnectionInputStream(final String jobName, final HttpURLConnection connection, final int code) throws IOException {\n        if (isRequestSucceed(code)) {\n            return connection.getInputStream();\n        }\n        log.warn(\"HTTP job {} executed with response code {}\", jobName, code);\n        return connection.getErrorStream();\n    }\n    \n    private boolean isRequestSucceed(final int httpStatusCode) {\n        return HttpURLConnection.HTTP_BAD_REQUEST > httpStatusCode;\n    }\n    \n    @Override\n    public String getType() {\n        return \"HTTP\";\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/http/src/main/java/org/apache/shardingsphere/elasticjob/http/pojo/HttpParam.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.http.pojo;\n\nimport com.google.common.base.Strings;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.http.props.HttpJobProperties;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\n\nimport java.util.Arrays;\nimport java.util.Properties;\n\n/**\n * Http job param.\n */\n@RequiredArgsConstructor\n@Getter\npublic final class HttpParam {\n    \n    private final String url;\n    \n    private final String method;\n    \n    private final String contentType;\n    \n    private final String data;\n    \n    private final int connectTimeoutMilliseconds;\n    \n    private final int readTimeoutMilliseconds;\n    \n    public HttpParam(final Properties props) {\n        url = props.getProperty(HttpJobProperties.URI_KEY);\n        if (Strings.isNullOrEmpty(url)) {\n            throw new JobConfigurationException(\"Cannot find HTTP URL, job is not executed.\");\n        }\n        method = props.getProperty(HttpJobProperties.METHOD_KEY);\n        if (Strings.isNullOrEmpty(method)) {\n            throw new JobConfigurationException(\"Cannot find HTTP method, job is not executed.\");\n        }\n        contentType = props.getProperty(HttpJobProperties.CONTENT_TYPE_KEY);\n        data = props.getProperty(HttpJobProperties.DATA_KEY);\n        connectTimeoutMilliseconds = Integer.parseInt(props.getProperty(HttpJobProperties.CONNECT_TIMEOUT_KEY, \"3000\"));\n        readTimeoutMilliseconds = Integer.parseInt(props.getProperty(HttpJobProperties.READ_TIMEOUT_KEY, \"5000\"));\n    }\n    \n    /**\n     * Is write method.\n     * \n     * @return write method or not\n     */\n    public boolean isWriteMethod() {\n        return Arrays.asList(\"POST\", \"PUT\", \"DELETE\").contains(method.toUpperCase());\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/http/src/main/java/org/apache/shardingsphere/elasticjob/http/props/HttpJobProperties.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.http.props;\n\n/**\n * HTTP job properties.\n */\npublic final class HttpJobProperties {\n    \n    /**\n     * HTTP request URI.\n     */\n    public static final String URI_KEY = \"http.uri\";\n    \n    /**\n     * Http request method.\n     */\n    public static final String METHOD_KEY = \"http.method\";\n    \n    /**\n     * HTTP request data.\n     */\n    public static final String DATA_KEY = \"http.data\";\n    \n    /**\n     * HTTP connect timeout in milliseconds.\n     */\n    public static final String CONNECT_TIMEOUT_KEY = \"http.connect.timeout.milliseconds\";\n    \n    /**\n     * HTTP read timeout in milliseconds.\n     */\n    public static final String READ_TIMEOUT_KEY = \"http.read.timeout.milliseconds\";\n    \n    /**\n     * HTTP content type.\n     */\n    public static final String CONTENT_TYPE_KEY = \"http.content.type\";\n    \n    /**\n     * HTTP sharding context.\n     */\n    public static final String SHARDING_CONTEXT_KEY = \"shardingContext\";\n}\n"
  },
  {
    "path": "ecosystem/executor/http/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.TypedJobItemExecutor",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.http.executor.HttpJobExecutor\n"
  },
  {
    "path": "ecosystem/executor/http/src/test/java/org/apache/shardingsphere/elasticjob/http/executor/HttpJobExecutorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.http.executor;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.http.executor.fixture.InternalController;\nimport org.apache.shardingsphere.elasticjob.http.props.HttpJobProperties;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionException;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulService;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulServiceConfiguration;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.mockito.Mockito.lenient;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass HttpJobExecutorTest {\n    \n    private static final int PORT = 9876;\n    \n    private static final String HOST = \"localhost\";\n    \n    private static RestfulService restfulService;\n    \n    @Mock\n    private ElasticJob elasticJob;\n    \n    @Mock\n    private JobConfiguration jobConfig;\n    \n    @Mock\n    private JobRuntimeService jobRuntimeService;\n    \n    // TODO We should not use `Mock.Strictness.LENIENT` here, but the default. This is a flaw in the unit test design.\n    @Mock(strictness = Mock.Strictness.LENIENT)\n    private Properties properties;\n    \n    @Mock\n    private ShardingContext shardingContext;\n    \n    private HttpJobExecutor jobExecutor;\n    \n    @BeforeAll\n    static void init() {\n        NettyRestfulServiceConfiguration config = new NettyRestfulServiceConfiguration(PORT);\n        config.setHost(HOST);\n        config.addControllerInstances(new InternalController());\n        restfulService = new NettyRestfulService(config);\n        restfulService.startup();\n    }\n    \n    @BeforeEach\n    void setUp() {\n        lenient().when(jobConfig.getProps()).thenReturn(properties);\n        jobExecutor = new HttpJobExecutor();\n    }\n    \n    @AfterAll\n    static void close() {\n        if (null != restfulService) {\n            restfulService.shutdown();\n        }\n    }\n    \n    @Test\n    void assertProcessWithoutSuccessCode() {\n        when(jobConfig.getProps().getProperty(HttpJobProperties.URI_KEY)).thenReturn(getRequestUri(\"/unknownMethod\"));\n        when(jobConfig.getProps().getProperty(HttpJobProperties.METHOD_KEY)).thenReturn(\"GET\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.DATA_KEY)).thenReturn(\"\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.CONNECT_TIMEOUT_KEY, \"3000\")).thenReturn(\"4000\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.READ_TIMEOUT_KEY, \"5000\")).thenReturn(\"5000\");\n        jobExecutor.process(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n    }\n    \n    @Test\n    void assertProcessWithGet() {\n        when(jobConfig.getProps().getProperty(HttpJobProperties.URI_KEY)).thenReturn(getRequestUri(\"/getName\"));\n        when(jobConfig.getProps().getProperty(HttpJobProperties.METHOD_KEY)).thenReturn(\"GET\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.DATA_KEY)).thenReturn(\"\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.CONNECT_TIMEOUT_KEY, \"3000\")).thenReturn(\"4000\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.READ_TIMEOUT_KEY, \"5000\")).thenReturn(\"5000\");\n        jobExecutor.process(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n    }\n    \n    @Test\n    void assertProcessHeader() {\n        when(jobConfig.getProps().getProperty(HttpJobProperties.URI_KEY)).thenReturn(getRequestUri(\"/getShardingContext\"));\n        when(jobConfig.getProps().getProperty(HttpJobProperties.METHOD_KEY)).thenReturn(\"GET\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.CONNECT_TIMEOUT_KEY, \"3000\")).thenReturn(\"4000\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.READ_TIMEOUT_KEY, \"5000\")).thenReturn(\"5000\");\n        jobExecutor.process(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n    }\n    \n    @Test\n    void assertProcessWithPost() {\n        when(jobConfig.getProps().getProperty(HttpJobProperties.URI_KEY)).thenReturn(getRequestUri(\"/updateName\"));\n        when(jobConfig.getProps().getProperty(HttpJobProperties.METHOD_KEY)).thenReturn(\"POST\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.DATA_KEY)).thenReturn(\"name=elasticjob\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.CONNECT_TIMEOUT_KEY, \"3000\")).thenReturn(\"4000\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.READ_TIMEOUT_KEY, \"5000\")).thenReturn(\"5000\");\n        when(jobConfig.getProps().getProperty(HttpJobProperties.CONTENT_TYPE_KEY)).thenReturn(\"application/x-www-form-urlencoded\");\n        jobExecutor.process(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n    }\n    \n    @Test\n    void assertProcessWithIOException() {\n        assertThrows(JobExecutionException.class, () -> {\n            when(jobConfig.getProps().getProperty(HttpJobProperties.URI_KEY)).thenReturn(getRequestUri(\"/postWithTimeout\"));\n            when(jobConfig.getProps().getProperty(HttpJobProperties.METHOD_KEY)).thenReturn(\"POST\");\n            when(jobConfig.getProps().getProperty(HttpJobProperties.DATA_KEY)).thenReturn(\"name=elasticjob\");\n            when(jobConfig.getProps().getProperty(HttpJobProperties.CONNECT_TIMEOUT_KEY, \"3000\")).thenReturn(\"1\");\n            when(jobConfig.getProps().getProperty(HttpJobProperties.READ_TIMEOUT_KEY, \"5000\")).thenReturn(\"1\");\n            jobExecutor.process(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n        });\n    }\n    \n    @Test\n    void assertGetType() {\n        assertThat(jobExecutor.getType(), is(\"HTTP\"));\n    }\n    \n    private String getRequestUri(final String path) {\n        return \"http://\" + HOST + \":\" + PORT + path;\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/http/src/test/java/org/apache/shardingsphere/elasticjob/http/executor/fixture/InternalController.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.http.executor.fixture;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulController;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Mapping;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Param;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.ParamSource;\nimport org.awaitility.Awaitility;\n\nimport java.util.Objects;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Slf4j\npublic final class InternalController implements RestfulController {\n    \n    /**\n     * Get name.\n     *\n     * @return control name\n     */\n    @Mapping(method = Http.GET, path = \"/getName\")\n    public String getName() {\n        return \"ejob\";\n    }\n    \n    /**\n     * Get sharding context.\n     *\n     * @param shardingContext sharding context\n     * @return sharding context\n     */\n    @Mapping(method = Http.GET, path = \"/getShardingContext\")\n    public String getShardingContext(@Param(name = \"shardingContext\", source = ParamSource.HEADER) final String shardingContext) {\n        Objects.nonNull(shardingContext);\n        return shardingContext;\n    }\n    \n    /**\n     * Update name.\n     *\n     * @param updateName the name\n     * @return updated name\n     */\n    @Mapping(method = Http.POST, path = \"/{updateName}\")\n    public String postName(@Param(name = \"updateName\", source = ParamSource.PATH) final String updateName) {\n        Objects.nonNull(updateName);\n        return updateName;\n    }\n    \n    /**\n     * Post with 100 mills delay for request IO Exception.\n     *\n     * @return \"ejob\"\n     */\n    @Mapping(method = Http.POST, path = \"/postWithTimeout\")\n    public String postWithTimeout() {\n        Awaitility.await().atLeast(100L, TimeUnit.MILLISECONDS).atMost(1L, TimeUnit.SECONDS).untilAsserted(() -> assertThat(Boolean.TRUE, is(Boolean.TRUE)));\n        return \"ejob\";\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/http/src/test/java/org/apache/shardingsphere/elasticjob/http/pojo/HttpParamTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.http.pojo;\n\nimport org.apache.shardingsphere.elasticjob.http.props.HttpJobProperties;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass HttpParamTest {\n    \n    @Test\n    void assertNewWithEmptyUrl() {\n        assertThrows(JobConfigurationException.class, () -> new HttpParam(new Properties()));\n    }\n    \n    @Test\n    void assertNewWithEmptyMethod() {\n        Properties props = new Properties();\n        props.setProperty(HttpJobProperties.URI_KEY, \"foo/url\");\n        assertThrows(JobConfigurationException.class, () -> new HttpParam(props));\n    }\n    \n    @Test\n    void assertNew() {\n        Properties props = new Properties();\n        props.setProperty(HttpJobProperties.URI_KEY, \"foo/url\");\n        props.setProperty(HttpJobProperties.METHOD_KEY, \"POST\");\n        HttpParam actual = new HttpParam(props);\n        assertThat(actual.getUrl(), is(\"foo/url\"));\n        assertThat(actual.getMethod(), is(\"POST\"));\n        assertThat(actual.getConnectTimeoutMilliseconds(), is(3000));\n        assertThat(actual.getReadTimeoutMilliseconds(), is(5000));\n    }\n    \n    @Test\n    void assertIsWriteMethodWithGet() {\n        Properties props = new Properties();\n        props.setProperty(HttpJobProperties.URI_KEY, \"foo/url\");\n        props.setProperty(HttpJobProperties.METHOD_KEY, \"GET\");\n        HttpParam actual = new HttpParam(props);\n        assertFalse(actual.isWriteMethod());\n    }\n    \n    @Test\n    void assertIsWriteMethodWithPost() {\n        Properties props = new Properties();\n        props.setProperty(HttpJobProperties.URI_KEY, \"foo/url\");\n        props.setProperty(HttpJobProperties.METHOD_KEY, \"POST\");\n        HttpParam actual = new HttpParam(props);\n        assertTrue(actual.isWriteMethod());\n    }\n    \n    @Test\n    void assertIsWriteMethodWithPut() {\n        Properties props = new Properties();\n        props.setProperty(HttpJobProperties.URI_KEY, \"foo/url\");\n        props.setProperty(HttpJobProperties.METHOD_KEY, \"PUT\");\n        HttpParam actual = new HttpParam(props);\n        assertTrue(actual.isWriteMethod());\n    }\n    \n    @Test\n    void assertIsWriteMethodWithDelete() {\n        Properties props = new Properties();\n        props.setProperty(HttpJobProperties.URI_KEY, \"foo/url\");\n        props.setProperty(HttpJobProperties.METHOD_KEY, \"DELETE\");\n        HttpParam actual = new HttpParam(props);\n        assertTrue(actual.isWriteMethod());\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/http/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n            <level>ERROR</level>\n        </filter>\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n</configuration>\n"
  },
  {
    "path": "ecosystem/executor/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-ecosystem</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-executor</artifactId>\n    <packaging>pom</packaging>\n    <name>${project.artifactId}</name>\n    \n    <modules>\n        <module>simple</module>\n        <module>dataflow</module>\n        <module>script</module>\n        <module>http</module>\n    </modules>\n</project>\n"
  },
  {
    "path": "ecosystem/executor/script/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-executor</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-script-executor</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-exec</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "ecosystem/executor/script/src/main/java/org/apache/shardingsphere/elasticjob/script/executor/ScriptJobExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.script.executor;\n\nimport com.google.common.base.Strings;\nimport org.apache.commons.exec.CommandLine;\nimport org.apache.commons.exec.DefaultExecutor;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.TypedJobItemExecutor;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.json.GsonFactory;\nimport org.apache.shardingsphere.elasticjob.script.props.ScriptJobProperties;\n\nimport java.io.IOException;\nimport java.util.Properties;\n\n/**\n * Script job executor.\n */\npublic final class ScriptJobExecutor implements TypedJobItemExecutor {\n    \n    @Override\n    public void process(final ElasticJob elasticJob, final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService, final ShardingContext shardingContext) {\n        CommandLine commandLine = CommandLine.parse(getScriptCommandLine(jobConfig.getProps()));\n        commandLine.addArgument(GsonFactory.getGson().toJson(shardingContext), false);\n        try {\n            new DefaultExecutor().execute(commandLine);\n        } catch (final IOException ex) {\n            throw new JobSystemException(\"Execute script failure.\", ex);\n        }\n    }\n    \n    private String getScriptCommandLine(final Properties props) {\n        String result = props.getProperty(ScriptJobProperties.SCRIPT_KEY);\n        if (Strings.isNullOrEmpty(result)) {\n            throw new JobConfigurationException(\"Cannot find script command line, job is not executed.\");\n        }\n        return result;\n    }\n    \n    @Override\n    public String getType() {\n        return \"SCRIPT\";\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/script/src/main/java/org/apache/shardingsphere/elasticjob/script/props/ScriptJobProperties.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.script.props;\n\n/**\n * Script job properties.\n */\npublic final class ScriptJobProperties {\n    \n    /**\n     * Script command line to be executed.\n     */\n    public static final String SCRIPT_KEY = \"script.command.line\";\n}\n"
  },
  {
    "path": "ecosystem/executor/script/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.TypedJobItemExecutor",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.script.executor.ScriptJobExecutor\n"
  },
  {
    "path": "ecosystem/executor/script/src/test/java/org/apache/shardingsphere/elasticjob/script/ScriptJobExecutorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.script;\n\nimport org.apache.commons.exec.OS;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.apache.shardingsphere.elasticjob.script.executor.ScriptJobExecutor;\nimport org.apache.shardingsphere.elasticjob.script.props.ScriptJobProperties;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ScriptJobExecutorTest {\n    \n    @Mock\n    private ElasticJob elasticJob;\n    \n    @Mock\n    private JobConfiguration jobConfig;\n    \n    @Mock\n    private JobRuntimeService jobRuntimeService;\n    \n    @Mock\n    private Properties properties;\n    \n    @Mock\n    private ShardingContext shardingContext;\n    \n    private ScriptJobExecutor jobExecutor;\n    \n    @BeforeEach\n    void setUp() {\n        jobExecutor = new ScriptJobExecutor();\n    }\n    \n    @Test\n    void assertProcessWithJobConfigurationException() {\n        assertThrows(JobConfigurationException.class, () -> {\n            when(jobConfig.getProps()).thenReturn(properties);\n            jobExecutor.process(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n        });\n    }\n    \n    @Test\n    void assertProcessWithJobSystemException() {\n        assertThrows(JobSystemException.class, () -> {\n            when(jobConfig.getProps()).thenReturn(properties);\n            when(properties.getProperty(ScriptJobProperties.SCRIPT_KEY)).thenReturn(\"demo.sh\");\n            jobExecutor.process(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n        });\n    }\n    \n    @Test\n    void assertProcess() {\n        when(jobConfig.getProps()).thenReturn(properties);\n        when(properties.getProperty(ScriptJobProperties.SCRIPT_KEY)).thenReturn(determineCommandByPlatform());\n        jobExecutor.process(elasticJob, jobConfig, jobRuntimeService, shardingContext);\n    }\n    \n    private String determineCommandByPlatform() {\n        return OS.isFamilyWindows() ? getWindowsEcho() : getEcho();\n    }\n    \n    private String getWindowsEcho() {\n        return \"cmd /c echo script-job\";\n    }\n    \n    private String getEcho() {\n        return \"echo script-job\";\n    }\n    \n    @Test\n    void assertGetType() {\n        assertThat(jobExecutor.getType(), is(\"SCRIPT\"));\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/simple/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-executor</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-simple-executor</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "ecosystem/executor/simple/src/main/java/org/apache/shardingsphere/elasticjob/simple/executor/SimpleJobExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.simple.executor;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\n\n/**\n * Simple job executor.\n */\npublic final class SimpleJobExecutor implements ClassedJobItemExecutor<SimpleJob> {\n    \n    @Override\n    public void process(final SimpleJob elasticJob, final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService, final ShardingContext shardingContext) {\n        elasticJob.execute(shardingContext);\n    }\n    \n    @Override\n    public Class<SimpleJob> getElasticJobClass() {\n        return SimpleJob.class;\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/simple/src/main/java/org/apache/shardingsphere/elasticjob/simple/job/SimpleJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.simple.job;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\n/**\n * Simple job.\n */\npublic interface SimpleJob extends ElasticJob {\n    \n    /**\n     * Execute job.\n     *\n     * @param shardingContext sharding context\n     */\n    void execute(ShardingContext shardingContext);\n}\n"
  },
  {
    "path": "ecosystem/executor/simple/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.simple.executor.SimpleJobExecutor\n"
  },
  {
    "path": "ecosystem/executor/simple/src/test/java/org/apache/shardingsphere/elasticjob/simple/executor/SimpleJobExecutorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.simple.executor;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.simple.job.FooSimpleJob;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass SimpleJobExecutorTest {\n    \n    @Mock\n    private FooSimpleJob fooSimpleJob;\n    \n    @Mock\n    private JobConfiguration jobConfig;\n    \n    @Mock\n    private JobRuntimeService jobRuntimeService;\n    \n    private SimpleJobExecutor jobExecutor;\n    \n    @BeforeEach\n    void setUp() {\n        jobExecutor = new SimpleJobExecutor();\n    }\n    \n    @Test\n    void assertProcess() {\n        jobExecutor.process(fooSimpleJob, jobConfig, jobRuntimeService, any());\n        verify(fooSimpleJob, times(1)).execute(any());\n    }\n    \n    @Test\n    void assertGetElasticJobClass() {\n        assertThat(jobExecutor.getElasticJobClass(), is(SimpleJob.class));\n    }\n}\n"
  },
  {
    "path": "ecosystem/executor/simple/src/test/java/org/apache/shardingsphere/elasticjob/simple/job/FooSimpleJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.simple.job;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\n@Getter\npublic final class FooSimpleJob implements SimpleJob {\n    \n    private volatile boolean completed;\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        completed = true;\n    }\n}\n"
  },
  {
    "path": "ecosystem/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-ecosystem</artifactId>\n    <packaging>pom</packaging>\n    <name>${project.artifactId}</name>\n    \n    <modules>\n        <module>executor</module>\n        <module>error-handler</module>\n        <module>tracing</module>\n    </modules>\n</project>\n"
  },
  {
    "path": "ecosystem/tracing/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-ecosystem</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-tracing</artifactId>\n    <packaging>pom</packaging>\n    <name>${project.artifactId}</name>\n    \n    <modules>\n        <module>rdb</module>\n    </modules>\n</project>\n"
  },
  {
    "path": "ecosystem/tracing/rdb/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-tracing</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-tracing-rdb</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-test-util</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/config/RDBTracingStorageConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.config;\n\nimport com.google.common.base.CaseFormat;\nimport com.google.common.base.Joiner;\nimport com.google.common.base.Objects;\nimport com.google.common.collect.Sets;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.SneakyThrows;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.datasource.DataSourceRegistry;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.datasource.JDBCParameterDecorator;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\n\nimport javax.sql.DataSource;\nimport java.lang.reflect.Method;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\n\n/**\n * RDB tracing storage configuration.\n */\n@RequiredArgsConstructor\n@Getter\npublic final class RDBTracingStorageConfiguration implements TracingStorageConfiguration<DataSource> {\n    \n    private static final String GETTER_PREFIX = \"get\";\n    \n    private static final String SETTER_PREFIX = \"set\";\n    \n    private static final Collection<Class<?>> GENERAL_CLASS_TYPE;\n    \n    private static final Collection<String> SKIPPED_PROPERTY_NAMES;\n    \n    static {\n        GENERAL_CLASS_TYPE = Sets.newHashSet(boolean.class, Boolean.class, int.class, Integer.class, long.class, Long.class, String.class, Collection.class, List.class);\n        SKIPPED_PROPERTY_NAMES = Sets.newHashSet(\"loginTimeout\");\n    }\n    \n    private final String dataSourceClassName;\n    \n    private final Map<String, Object> props = new LinkedHashMap<>();\n    \n    /**\n     * Get data source configuration.\n     *\n     * @param dataSource data source\n     * @return data source configuration\n     */\n    public static RDBTracingStorageConfiguration getDataSourceConfiguration(final DataSource dataSource) {\n        RDBTracingStorageConfiguration result = new RDBTracingStorageConfiguration(dataSource.getClass().getName());\n        result.props.putAll(findAllGetterProperties(dataSource));\n        return result;\n    }\n    \n    @SneakyThrows(ReflectiveOperationException.class)\n    private static Map<String, Object> findAllGetterProperties(final Object target) {\n        Collection<Method> allGetterMethods = findAllGetterMethods(target.getClass());\n        Map<String, Object> result = new LinkedHashMap<>(allGetterMethods.size(), 1);\n        for (Method each : allGetterMethods) {\n            String propertyName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, each.getName().substring(GETTER_PREFIX.length()));\n            if (GENERAL_CLASS_TYPE.contains(each.getReturnType()) && !SKIPPED_PROPERTY_NAMES.contains(propertyName)) {\n                Optional.ofNullable(each.invoke(target)).ifPresent(propertyValue -> result.put(propertyName, propertyValue));\n            }\n        }\n        return result;\n    }\n    \n    private static Collection<Method> findAllGetterMethods(final Class<?> clazz) {\n        Method[] methods = clazz.getMethods();\n        Collection<Method> result = new HashSet<>(methods.length);\n        for (Method each : methods) {\n            if (each.getName().startsWith(GETTER_PREFIX) && 0 == each.getParameterTypes().length) {\n                result.add(each);\n            }\n        }\n        return result;\n    }\n    \n    /**\n     * Create data source.\n     *\n     * @return data source\n     */\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    @SneakyThrows(ReflectiveOperationException.class)\n    public DataSource createDataSource() {\n        DataSource result = (DataSource) Class.forName(dataSourceClassName).getConstructor().newInstance();\n        Method[] methods = result.getClass().getMethods();\n        for (Entry<String, Object> entry : props.entrySet()) {\n            if (SKIPPED_PROPERTY_NAMES.contains(entry.getKey())) {\n                continue;\n            }\n            Optional<Method> setterMethod = findSetterMethod(methods, entry.getKey());\n            if (setterMethod.isPresent()) {\n                setterMethod.get().invoke(result, entry.getValue());\n            }\n        }\n        Optional<JDBCParameterDecorator> decorator = TypedSPILoader.findService(JDBCParameterDecorator.class, result.getClass());\n        return decorator.isPresent() ? decorator.get().decorate(result) : result;\n    }\n    \n    private Optional<Method> findSetterMethod(final Method[] methods, final String property) {\n        String setterMethodName = Joiner.on(\"\").join(SETTER_PREFIX, CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, property));\n        for (Method each : methods) {\n            if (each.getName().equals(setterMethodName) && 1 == each.getParameterTypes().length) {\n                return Optional.of(each);\n            }\n        }\n        return Optional.empty();\n    }\n    \n    @Override\n    public DataSource getStorage() {\n        return DataSourceRegistry.getInstance().getDataSource(this);\n    }\n    \n    @Override\n    public boolean equals(final Object obj) {\n        return this == obj || null != obj && getClass() == obj.getClass() && equalsByProperties((RDBTracingStorageConfiguration) obj);\n    }\n    \n    private boolean equalsByProperties(final RDBTracingStorageConfiguration dataSourceConfig) {\n        return dataSourceClassName.equals(dataSourceConfig.dataSourceClassName) && props.equals(dataSourceConfig.props);\n    }\n    \n    @Override\n    public int hashCode() {\n        return Objects.hashCode(dataSourceClassName, props);\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/listener/RDBTracingListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListener;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository;\n\nimport javax.sql.DataSource;\nimport java.sql.SQLException;\n\n/**\n * RDB tracing listener.\n */\npublic final class RDBTracingListener implements TracingListener {\n    \n    private final RDBJobEventRepository repository;\n    \n    public RDBTracingListener(final DataSource dataSource) throws SQLException {\n        repository = RDBJobEventRepository.getInstance(dataSource);\n    }\n    \n    @Override\n    public void listen(final JobExecutionEvent executionEvent) {\n        repository.addJobExecutionEvent(executionEvent);\n    }\n    \n    @Override\n    public void listen(final JobStatusTraceEvent jobStatusTraceEvent) {\n        repository.addJobStatusTraceEvent(jobStatusTraceEvent);\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/listener/RDBTracingListenerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.tracing.exception.TracingConfigurationException;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListener;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListenerFactory;\n\nimport javax.sql.DataSource;\nimport java.sql.SQLException;\n\n/**\n * RDB tracing listener factory.\n */\npublic final class RDBTracingListenerFactory implements TracingListenerFactory<DataSource> {\n    \n    @Override\n    public TracingListener create(final DataSource storage) throws TracingConfigurationException {\n        try {\n            return new RDBTracingListener(storage);\n        } catch (final SQLException ex) {\n            throw new TracingConfigurationException(ex);\n        }\n    }\n    \n    @Override\n    public String getType() {\n        return \"RDB\";\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/converter/RDBTracingStorageConfigurationConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.converter;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.exception.TracingStorageUnavailableException;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfigurationConverter;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.config.RDBTracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.datasource.DataSourceRegistry;\n\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\n/**\n * RDB tracing storage converter.\n */\n@Slf4j\npublic final class RDBTracingStorageConfigurationConverter implements TracingStorageConfigurationConverter<DataSource> {\n    \n    @Override\n    public TracingStorageConfiguration<DataSource> toConfiguration(final DataSource dataSource) {\n        try (Connection connection = dataSource.getConnection()) {\n            log.trace(\"Try to get connection from {}\", connection.getMetaData().getURL());\n        } catch (final SQLException ex) {\n            log.error(ex.getLocalizedMessage(), ex);\n            throw new TracingStorageUnavailableException(ex);\n        }\n        RDBTracingStorageConfiguration result = RDBTracingStorageConfiguration.getDataSourceConfiguration(dataSource);\n        DataSourceRegistry.getInstance().registerDataSource(result, dataSource);\n        return result;\n    }\n    \n    @Override\n    public Class<DataSource> storageType() {\n        return DataSource.class;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/datasource/DataSourceRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.datasource;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.config.RDBTracingStorageConfiguration;\n\nimport javax.sql.DataSource;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * Mapping tracing storage configuration to data source.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class DataSourceRegistry {\n    \n    private static volatile DataSourceRegistry instance;\n    \n    private final ConcurrentMap<RDBTracingStorageConfiguration, DataSource> dataSources = new ConcurrentHashMap<>();\n    \n    /**\n     * Get instance of {@link DataSourceRegistry}.\n     *\n     * @return {@link DataSourceRegistry} singleton\n     */\n    public static DataSourceRegistry getInstance() {\n        if (null == instance) {\n            synchronized (DataSourceRegistry.class) {\n                if (null == instance) {\n                    instance = new DataSourceRegistry();\n                }\n            }\n        }\n        return instance;\n    }\n    \n    /**\n     * Register data source.\n     * \n     * @param dataSourceConfig data source configuration\n     * @param dataSource data source\n     */\n    public void registerDataSource(final RDBTracingStorageConfiguration dataSourceConfig, final DataSource dataSource) {\n        dataSources.putIfAbsent(dataSourceConfig, dataSource);\n    }\n    \n    /**\n     * Get {@link DataSource} by {@link RDBTracingStorageConfiguration}.\n     *\n     * @param dataSourceConfig data source configuration\n     * @return instance of {@link DataSource}\n     */\n    public DataSource getDataSource(final RDBTracingStorageConfiguration dataSourceConfig) {\n        return dataSources.computeIfAbsent(dataSourceConfig, RDBTracingStorageConfiguration::createDataSource);\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/datasource/JDBCParameterDecorator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.datasource;\n\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;\n\nimport javax.sql.DataSource;\n\n/**\n * JDBC parameter decorator.\n * \n * @param <T> type of data source\n */\npublic interface JDBCParameterDecorator<T extends DataSource> extends TypedSPI {\n    \n    /**\n     * Decorate data source.\n     * \n     * @param dataSource data source to be decorated\n     * @return decorated data source\n     */\n    T decorate(T dataSource);\n    \n    @Override\n    Class<T> getType();\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/repository/RDBJobEventRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository;\n\nimport com.google.common.base.Strings;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent.State;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.exception.TracingStorageUnavailableException;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.sql.RDBStorageSQLMapper;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.sql.SQLPropertiesFactory;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.DefaultTracingStorageDatabaseType;\nimport org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;\n\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Timestamp;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Supplier;\n\n/**\n * RDB job event repository.\n */\n@Slf4j\npublic final class RDBJobEventRepository {\n    \n    private static final String TABLE_JOB_EXECUTION_LOG = \"JOB_EXECUTION_LOG\";\n    \n    private static final String TABLE_JOB_STATUS_TRACE_LOG = \"JOB_STATUS_TRACE_LOG\";\n    \n    private static final String TASK_ID_STATE_INDEX = \"TASK_ID_STATE_INDEX\";\n    \n    private static final Map<DataSource, RDBJobEventRepository> STORAGE_MAP = new ConcurrentHashMap<>();\n    \n    private final DataSource dataSource;\n    \n    private final TracingStorageDatabaseType tracingStorageDatabaseType;\n    \n    private final RDBStorageSQLMapper sqlMapper;\n    \n    private RDBJobEventRepository(final DataSource dataSource) throws SQLException {\n        this.dataSource = dataSource;\n        tracingStorageDatabaseType = getTracingStorageDatabaseType(dataSource);\n        sqlMapper = new RDBStorageSQLMapper(SQLPropertiesFactory.getProperties(tracingStorageDatabaseType));\n        initTablesAndIndexes();\n    }\n    \n    /**\n     * The same data source always return the same RDB job event repository instance.\n     *\n     * @param dataSource dataSource\n     * @return RDBJobEventStorage instance\n     * @throws SQLException SQLException\n     */\n    public static RDBJobEventRepository getInstance(final DataSource dataSource) throws SQLException {\n        return getInstance(() -> STORAGE_MAP.computeIfAbsent(dataSource, ds -> {\n            try {\n                return new RDBJobEventRepository(ds);\n            } catch (final SQLException ex) {\n                throw new TracingStorageUnavailableException(ex);\n            }\n        }));\n    }\n    \n    private static RDBJobEventRepository getInstance(final Supplier<RDBJobEventRepository> supplier) throws SQLException {\n        try {\n            return supplier.get();\n        } catch (final TracingStorageUnavailableException ex) {\n            if (ex.getCause() instanceof SQLException) {\n                throw new SQLException(ex.getCause());\n            }\n            throw ex;\n        }\n    }\n    \n    private TracingStorageDatabaseType getTracingStorageDatabaseType(final DataSource dataSource) throws SQLException {\n        try (Connection connection = dataSource.getConnection()) {\n            String databaseProductName = connection.getMetaData().getDatabaseProductName();\n            for (TracingStorageDatabaseType each : ShardingSphereServiceLoader.getServiceInstances(TracingStorageDatabaseType.class)) {\n                if (each.getDatabaseProductName().equals(databaseProductName)) {\n                    return each;\n                }\n            }\n        }\n        return new DefaultTracingStorageDatabaseType();\n    }\n    \n    private void initTablesAndIndexes() throws SQLException {\n        try (Connection connection = dataSource.getConnection()) {\n            createJobExecutionTableAndIndexIfNeeded(connection);\n            createJobStatusTraceTableAndIndexIfNeeded(connection);\n        }\n    }\n    \n    private void createJobExecutionTableAndIndexIfNeeded(final Connection connection) throws SQLException {\n        if (existsTable(connection, TABLE_JOB_EXECUTION_LOG) || existsTable(connection, TABLE_JOB_EXECUTION_LOG.toLowerCase())) {\n            return;\n        }\n        createJobExecutionTable(connection);\n    }\n    \n    private void createJobStatusTraceTableAndIndexIfNeeded(final Connection connection) throws SQLException {\n        if (existsTable(connection, TABLE_JOB_STATUS_TRACE_LOG) || existsTable(connection, TABLE_JOB_STATUS_TRACE_LOG.toLowerCase())) {\n            return;\n        }\n        createJobStatusTraceTable(connection);\n        createTaskIdIndexIfNeeded(connection);\n    }\n    \n    private boolean existsTable(final Connection connection, final String tableName) throws SQLException {\n        DatabaseMetaData dbMetaData = connection.getMetaData();\n        try (ResultSet resultSet = dbMetaData.getTables(connection.getCatalog(), null, tableName, new String[]{\"TABLE\"})) {\n            return resultSet.next();\n        }\n    }\n    \n    private void createTaskIdIndexIfNeeded(final Connection connection) throws SQLException {\n        if (existsIndex(connection, TABLE_JOB_STATUS_TRACE_LOG, TASK_ID_STATE_INDEX) || existsIndex(connection, TABLE_JOB_STATUS_TRACE_LOG.toLowerCase(), TASK_ID_STATE_INDEX.toLowerCase())) {\n            return;\n        }\n        createTaskIdAndStateIndex(connection);\n    }\n    \n    private boolean existsIndex(final Connection connection, final String tableName, final String indexName) throws SQLException {\n        DatabaseMetaData dbMetaData = connection.getMetaData();\n        try (ResultSet resultSet = dbMetaData.getIndexInfo(connection.getCatalog(), null, tableName, false, false)) {\n            while (resultSet.next()) {\n                if (indexName.equals(resultSet.getString(\"INDEX_NAME\"))) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n    \n    private void createJobExecutionTable(final Connection connection) throws SQLException {\n        try (PreparedStatement preparedStatement = connection.prepareStatement(sqlMapper.getCreateTableForJobExecutionLog())) {\n            preparedStatement.execute();\n        }\n    }\n    \n    private void createJobStatusTraceTable(final Connection connection) throws SQLException {\n        try (PreparedStatement preparedStatement = connection.prepareStatement(sqlMapper.getCreateTableForJobStatusTraceLog())) {\n            preparedStatement.execute();\n        }\n    }\n    \n    private void createTaskIdAndStateIndex(final Connection connection) throws SQLException {\n        try (PreparedStatement preparedStatement = connection.prepareStatement(sqlMapper.getCreateIndexForTaskIdStateIndex())) {\n            preparedStatement.execute();\n        }\n    }\n    \n    /**\n     * Add job execution event.\n     * \n     * @param event job execution event\n     * @return add success or not\n     */\n    public boolean addJobExecutionEvent(final JobExecutionEvent event) {\n        if (null == event.getCompleteTime()) {\n            return insertJobExecutionEvent(event);\n        } else {\n            if (event.isSuccess()) {\n                return updateJobExecutionEventWhenSuccess(event);\n            } else {\n                return updateJobExecutionEventFailure(event);\n            }\n        }\n    }\n    \n    private boolean insertJobExecutionEvent(final JobExecutionEvent event) {\n        boolean result = false;\n        try (\n                Connection connection = dataSource.getConnection();\n                PreparedStatement preparedStatement = connection.prepareStatement(sqlMapper.getInsertForJobExecutionLog())) {\n            preparedStatement.setString(1, event.getId());\n            preparedStatement.setString(2, event.getJobName());\n            preparedStatement.setString(3, event.getTaskId());\n            preparedStatement.setString(4, event.getHostname());\n            preparedStatement.setString(5, event.getIp());\n            preparedStatement.setInt(6, event.getShardingItem());\n            preparedStatement.setString(7, event.getSource().toString());\n            preparedStatement.setBoolean(8, event.isSuccess());\n            preparedStatement.setTimestamp(9, new Timestamp(event.getStartTime().getTime()));\n            preparedStatement.execute();\n            result = true;\n        } catch (final SQLException ex) {\n            if (!isDuplicateRecord(ex)) {\n                // TODO log failure directly to output log, consider to be configurable in the future\n                log.error(ex.getMessage());\n            }\n        }\n        return result;\n    }\n    \n    private boolean updateJobExecutionEventWhenSuccess(final JobExecutionEvent event) {\n        boolean result = false;\n        try (\n                Connection connection = dataSource.getConnection();\n                PreparedStatement preparedStatement = connection.prepareStatement(sqlMapper.getUpdateForJobExecutionLog())) {\n            preparedStatement.setBoolean(1, event.isSuccess());\n            preparedStatement.setTimestamp(2, new Timestamp(event.getCompleteTime().getTime()));\n            preparedStatement.setString(3, event.getId());\n            if (0 == preparedStatement.executeUpdate()) {\n                return insertJobExecutionEventWhenSuccess(event);\n            }\n            result = true;\n        } catch (final SQLException ex) {\n            // TODO log failure directly to output log, consider to be configurable in the future\n            log.error(ex.getMessage());\n        }\n        return result;\n    }\n    \n    private boolean insertJobExecutionEventWhenSuccess(final JobExecutionEvent event) {\n        boolean result = false;\n        try (\n                Connection connection = dataSource.getConnection();\n                PreparedStatement preparedStatement = connection.prepareStatement(sqlMapper.getInsertForJobExecutionLogForComplete())) {\n            preparedStatement.setString(1, event.getId());\n            preparedStatement.setString(2, event.getJobName());\n            preparedStatement.setString(3, event.getTaskId());\n            preparedStatement.setString(4, event.getHostname());\n            preparedStatement.setString(5, event.getIp());\n            preparedStatement.setInt(6, event.getShardingItem());\n            preparedStatement.setString(7, event.getSource().toString());\n            preparedStatement.setBoolean(8, event.isSuccess());\n            preparedStatement.setTimestamp(9, new Timestamp(event.getStartTime().getTime()));\n            preparedStatement.setTimestamp(10, new Timestamp(event.getCompleteTime().getTime()));\n            preparedStatement.execute();\n            result = true;\n        } catch (final SQLException ex) {\n            if (isDuplicateRecord(ex)) {\n                return updateJobExecutionEventWhenSuccess(event);\n            }\n            // TODO log failure directly to output log, consider to be configurable in the future\n            log.error(ex.getMessage());\n        }\n        return result;\n    }\n    \n    private boolean updateJobExecutionEventFailure(final JobExecutionEvent event) {\n        boolean result = false;\n        try (\n                Connection connection = dataSource.getConnection();\n                PreparedStatement preparedStatement = connection.prepareStatement(sqlMapper.getUpdateForJobExecutionLogForFailure())) {\n            preparedStatement.setBoolean(1, event.isSuccess());\n            preparedStatement.setTimestamp(2, new Timestamp(event.getCompleteTime().getTime()));\n            preparedStatement.setString(3, truncateString(event.getFailureCause()));\n            preparedStatement.setString(4, event.getId());\n            if (0 == preparedStatement.executeUpdate()) {\n                return insertJobExecutionEventWhenFailure(event);\n            }\n            result = true;\n        } catch (final SQLException ex) {\n            // TODO log failure directly to output log, consider to be configurable in the future\n            log.error(ex.getMessage());\n        }\n        return result;\n    }\n    \n    private boolean insertJobExecutionEventWhenFailure(final JobExecutionEvent event) {\n        boolean result = false;\n        try (\n                Connection connection = dataSource.getConnection();\n                PreparedStatement preparedStatement = connection.prepareStatement(sqlMapper.getInsertForJobExecutionLogForFailure())) {\n            preparedStatement.setString(1, event.getId());\n            preparedStatement.setString(2, event.getJobName());\n            preparedStatement.setString(3, event.getTaskId());\n            preparedStatement.setString(4, event.getHostname());\n            preparedStatement.setString(5, event.getIp());\n            preparedStatement.setInt(6, event.getShardingItem());\n            preparedStatement.setString(7, event.getSource().toString());\n            preparedStatement.setString(8, truncateString(event.getFailureCause()));\n            preparedStatement.setBoolean(9, event.isSuccess());\n            preparedStatement.setTimestamp(10, new Timestamp(event.getStartTime().getTime()));\n            preparedStatement.execute();\n            result = true;\n        } catch (final SQLException ex) {\n            if (isDuplicateRecord(ex)) {\n                return updateJobExecutionEventFailure(event);\n            }\n            // TODO log failure directly to output log, consider to be configurable in the future\n            log.error(ex.getMessage());\n        }\n        return result;\n    }\n    \n    private boolean isDuplicateRecord(final SQLException ex) {\n        return null != tracingStorageDatabaseType && tracingStorageDatabaseType.getDuplicateRecordErrorCode() == ex.getErrorCode();\n    }\n    \n    /**\n     * Add job status trace event.\n     * \n     * @param event job status trace event\n     * @return add success or not\n     */\n    public boolean addJobStatusTraceEvent(final JobStatusTraceEvent event) {\n        String originalTaskId = event.getOriginalTaskId();\n        if (State.TASK_STAGING != event.getState()) {\n            originalTaskId = getOriginalTaskId(event.getTaskId());\n        }\n        boolean result = false;\n        try (\n                Connection connection = dataSource.getConnection();\n                PreparedStatement preparedStatement = connection.prepareStatement(sqlMapper.getInsertForJobStatusTraceLog())) {\n            preparedStatement.setString(1, UUID.randomUUID().toString());\n            preparedStatement.setString(2, event.getJobName());\n            preparedStatement.setString(3, originalTaskId);\n            preparedStatement.setString(4, event.getTaskId());\n            preparedStatement.setString(5, event.getSlaveId());\n            preparedStatement.setString(6, event.getExecutionType().name());\n            preparedStatement.setString(7, event.getShardingItems());\n            preparedStatement.setString(8, event.getState().toString());\n            preparedStatement.setString(9, truncateString(event.getMessage()));\n            preparedStatement.setTimestamp(10, new Timestamp(event.getCreationTime().getTime()));\n            preparedStatement.execute();\n            result = true;\n        } catch (final SQLException ex) {\n            // TODO log failure directly to output log, consider to be configurable in the future\n            log.error(ex.getMessage());\n        }\n        return result;\n    }\n    \n    private String getOriginalTaskId(final String taskId) {\n        String result = \"\";\n        try (\n                Connection connection = dataSource.getConnection();\n                PreparedStatement preparedStatement = connection.prepareStatement(sqlMapper.getSelectOriginalTaskIdForJobStatusTraceLog())) {\n            preparedStatement.setString(1, taskId);\n            try (ResultSet resultSet = preparedStatement.executeQuery()) {\n                if (resultSet.next()) {\n                    return resultSet.getString(\"original_task_id\");\n                }\n            }\n        } catch (final SQLException ex) {\n            // TODO log failure directly to output log, consider to be configurable in the future\n            log.error(ex.getMessage());\n        }\n        return result;\n    }\n    \n    private String truncateString(final String str) {\n        return !Strings.isNullOrEmpty(str) && str.length() > 4000 ? str.substring(0, 4000) : str;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/sql/RDBStorageSQLMapper.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.sql;\n\nimport lombok.Getter;\n\nimport java.util.Properties;\n\n/**\n * RDB storage SQL mapper.\n */\n@Getter\npublic final class RDBStorageSQLMapper {\n    \n    private final String createTableForJobExecutionLog;\n    \n    private final String createTableForJobStatusTraceLog;\n    \n    private final String createIndexForTaskIdStateIndex;\n    \n    private final String insertForJobExecutionLog;\n    \n    private final String insertForJobExecutionLogForComplete;\n    \n    private final String insertForJobExecutionLogForFailure;\n    \n    private final String updateForJobExecutionLog;\n    \n    private final String updateForJobExecutionLogForFailure;\n    \n    private final String insertForJobStatusTraceLog;\n    \n    private final String selectForJobStatusTraceLog;\n    \n    private final String selectOriginalTaskIdForJobStatusTraceLog;\n    \n    public RDBStorageSQLMapper(final Properties props) {\n        createTableForJobExecutionLog = props.getProperty(\"JOB_EXECUTION_LOG.TABLE.CREATE\");\n        createTableForJobStatusTraceLog = props.getProperty(\"JOB_STATUS_TRACE_LOG.TABLE.CREATE\");\n        createIndexForTaskIdStateIndex = props.getProperty(\"TASK_ID_STATE_INDEX.INDEX.CREATE\");\n        insertForJobExecutionLog = props.getProperty(\"JOB_EXECUTION_LOG.INSERT\");\n        insertForJobExecutionLogForComplete = props.getProperty(\"JOB_EXECUTION_LOG.INSERT_COMPLETE\");\n        insertForJobExecutionLogForFailure = props.getProperty(\"JOB_EXECUTION_LOG.INSERT_FAILURE\");\n        updateForJobExecutionLog = props.getProperty(\"JOB_EXECUTION_LOG.UPDATE\");\n        updateForJobExecutionLogForFailure = props.getProperty(\"JOB_EXECUTION_LOG.UPDATE_FAILURE\");\n        insertForJobStatusTraceLog = props.getProperty(\"JOB_STATUS_TRACE_LOG.INSERT\");\n        selectForJobStatusTraceLog = props.getProperty(\"JOB_STATUS_TRACE_LOG.SELECT\");\n        selectOriginalTaskIdForJobStatusTraceLog = props.getProperty(\"JOB_STATUS_TRACE_LOG.SELECT_ORIGINAL_TASK_ID\");\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/sql/SQLPropertiesFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.sql;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport lombok.SneakyThrows;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Properties;\n\n/**\n * SQL properties factory.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class SQLPropertiesFactory {\n    \n    /**\n     * Get SQL properties.\n     *\n     * @param type tracing storage database type\n     * @return SQL properties\n     */\n    public static Properties getProperties(final TracingStorageDatabaseType type) {\n        return loadProps(String.format(\"%s.properties\", type.getType()));\n    }\n    \n    @SneakyThrows(IOException.class)\n    private static Properties loadProps(final String sqlPropertiesFileName) {\n        Properties result = new Properties();\n        result.load(getPropertiesInputStream(sqlPropertiesFileName));\n        return result;\n    }\n    \n    private static InputStream getPropertiesInputStream(final String sqlPropertiesFileName) {\n        InputStream sqlPropertiesFile = SQLPropertiesFactory.class.getClassLoader().getResourceAsStream(String.format(\"META-INF/sql/%s\", sqlPropertiesFileName));\n        return null == sqlPropertiesFile ? SQLPropertiesFactory.class.getClassLoader().getResourceAsStream(\"META-INF/sql/SQL92.properties\") : sqlPropertiesFile;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/type/TracingStorageDatabaseType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.type;\n\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;\n\n/**\n * Tracing storage database type.\n */\n@SingletonSPI\npublic interface TracingStorageDatabaseType extends TypedSPI {\n    \n    /**\n     * Get database product name.\n     * \n     * @return database product name\n     */\n    default String getDatabaseProductName() {\n        return getType();\n    }\n    \n    /**\n     * Get duplicate record error code.\n     * \n     * @return duplicate record error code\n     */\n    int getDuplicateRecordErrorCode();\n    \n    @Override\n    String getType();\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/type/impl/DB2TracingStorageDatabaseType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl;\n\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType;\n\n/**\n * Tracing storage database type for DB2.\n */\npublic final class DB2TracingStorageDatabaseType implements TracingStorageDatabaseType {\n    \n    @Override\n    public String getType() {\n        return \"DB2\";\n    }\n    \n    @Override\n    public int getDuplicateRecordErrorCode() {\n        return -803;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/type/impl/DefaultTracingStorageDatabaseType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl;\n\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType;\n\n/**\n * Default tracing storage database type.\n */\npublic class DefaultTracingStorageDatabaseType implements TracingStorageDatabaseType {\n    \n    @Override\n    public String getType() {\n        return \"SQL92\";\n    }\n    \n    @Override\n    public int getDuplicateRecordErrorCode() {\n        return Integer.MIN_VALUE;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/type/impl/GaussDBTracingStorageDatabaseType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl;\n\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType;\n\n/**\n * Tracing storage database type for Gaussdb.\n */\npublic final class GaussDBTracingStorageDatabaseType implements TracingStorageDatabaseType {\n    \n    @Override\n    public String getType() {\n        return \"GaussDB\";\n    }\n    \n    @Override\n    public int getDuplicateRecordErrorCode() {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/type/impl/H2TracingStorageDatabaseType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl;\n\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType;\n\n/**\n * Tracing storage database type for H2.\n */\npublic final class H2TracingStorageDatabaseType implements TracingStorageDatabaseType {\n    \n    @Override\n    public String getType() {\n        return \"H2\";\n    }\n    \n    @Override\n    public int getDuplicateRecordErrorCode() {\n        return 23505;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/type/impl/MySQLTracingStorageDatabaseType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl;\n\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType;\n\n/**\n * Tracing storage database type for MySQL.\n */\npublic final class MySQLTracingStorageDatabaseType implements TracingStorageDatabaseType {\n    \n    @Override\n    public String getType() {\n        return \"MySQL\";\n    }\n    \n    @Override\n    public int getDuplicateRecordErrorCode() {\n        return 1062;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/type/impl/OracleTracingStorageDatabaseType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl;\n\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType;\n\n/**\n * Tracing storage database type for Oracle.\n */\npublic final class OracleTracingStorageDatabaseType implements TracingStorageDatabaseType {\n    \n    @Override\n    public String getType() {\n        return \"Oracle\";\n    }\n    \n    @Override\n    public int getDuplicateRecordErrorCode() {\n        return 1;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/type/impl/PostgreSQLTracingStorageDatabaseType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl;\n\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType;\n\n/**\n * Tracing storage database type for PostgreSQL.\n */\npublic final class PostgreSQLTracingStorageDatabaseType implements TracingStorageDatabaseType {\n    \n    @Override\n    public String getType() {\n        return \"PostgreSQL\";\n    }\n    \n    @Override\n    public int getDuplicateRecordErrorCode() {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/type/impl/SQLServerTracingStorageDatabaseType.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl;\n\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType;\n\n/**\n * Tracing storage database type for SQLServer.\n */\npublic final class SQLServerTracingStorageDatabaseType implements TracingStorageDatabaseType {\n    \n    @Override\n    public String getType() {\n        return \"SQLServer\";\n    }\n    \n    @Override\n    public String getDatabaseProductName() {\n        return \"Microsoft SQL Server\";\n    }\n    \n    @Override\n    public int getDuplicateRecordErrorCode() {\n        return 1;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/yaml/YamlDataSourceConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.yaml;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.config.RDBTracingStorageConfiguration;\n\nimport javax.sql.DataSource;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * YAML Data source configuration.\n */\n@Getter\n@Setter\npublic final class YamlDataSourceConfiguration implements YamlTracingStorageConfiguration<DataSource> {\n    \n    private static final long serialVersionUID = -8013707594458676772L;\n    \n    private String dataSourceClassName;\n    \n    private Map<String, Object> props = new LinkedHashMap<>();\n    \n    @Override\n    public TracingStorageConfiguration<DataSource> toConfiguration() {\n        RDBTracingStorageConfiguration result = new RDBTracingStorageConfiguration(dataSourceClassName);\n        result.getProps().putAll(props);\n        return result;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/java/org/apache/shardingsphere/elasticjob/tracing/rdb/yaml/YamlDataSourceConfigurationConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.yaml;\n\nimport org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfigurationConverter;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.config.RDBTracingStorageConfiguration;\n\nimport javax.sql.DataSource;\n\n/**\n * {@link YamlConfigurationConverter} for {@link YamlDataSourceConfiguration}.\n */\n@SuppressWarnings({\"rawtypes\", \"unchecked\"})\npublic final class YamlDataSourceConfigurationConverter implements YamlConfigurationConverter<TracingStorageConfiguration<DataSource>, YamlTracingStorageConfiguration<DataSource>> {\n    \n    @Override\n    public YamlTracingStorageConfiguration<DataSource> convertToYamlConfiguration(final TracingStorageConfiguration<DataSource> data) {\n        RDBTracingStorageConfiguration dataSourceConfig = (RDBTracingStorageConfiguration) data;\n        YamlDataSourceConfiguration result = new YamlDataSourceConfiguration();\n        result.setDataSourceClassName(dataSourceConfig.getDataSourceClassName());\n        result.setProps(dataSourceConfig.getProps());\n        return result;\n    }\n    \n    @Override\n    public Class getType() {\n        return RDBTracingStorageConfiguration.class;\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListenerFactory",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.tracing.rdb.listener.RDBTracingListenerFactory\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfigurationConverter",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.tracing.rdb.storage.converter.RDBTracingStorageConfigurationConverter\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfigurationConverter",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfigurationConverter\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.MySQLTracingStorageDatabaseType\norg.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.PostgreSQLTracingStorageDatabaseType\norg.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.OracleTracingStorageDatabaseType\norg.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.SQLServerTracingStorageDatabaseType\norg.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.DB2TracingStorageDatabaseType\norg.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.H2TracingStorageDatabaseType\norg.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.GaussDBTracingStorageDatabaseType\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/sql/DB2.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nJOB_EXECUTION_LOG.TABLE.CREATE=CREATE TABLE JOB_EXECUTION_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, task_id VARCHAR(255) NOT NULL, hostname VARCHAR(255) NOT NULL, ip VARCHAR(50) NOT NULL, sharding_item INT NOT NULL, execution_source VARCHAR(20) NOT NULL, failure_cause VARCHAR(4000) NULL, is_success INT NOT NULL, start_time TIMESTAMP NULL, complete_time TIMESTAMP NULL, PRIMARY KEY (id))\n\nJOB_EXECUTION_LOG.INSERT=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_COMPLETE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time, complete_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_FAILURE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, failure_cause, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.UPDATE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ? WHERE id = ?\nJOB_EXECUTION_LOG.UPDATE_FAILURE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ?, failure_cause = ? WHERE id = ?\n\nJOB_STATUS_TRACE_LOG.TABLE.CREATE=CREATE TABLE JOB_STATUS_TRACE_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, original_task_id VARCHAR(255) NOT NULL, task_id VARCHAR(255) NOT NULL, slave_id VARCHAR(50) NOT NULL, execution_type VARCHAR(20) NOT NULL, sharding_item VARCHAR(100) NOT NULL, state VARCHAR(20) NOT NULL, message VARCHAR(4000) NULL, creation_time TIMESTAMP NULL, PRIMARY KEY (id))\nTASK_ID_STATE_INDEX.INDEX.CREATE=CREATE INDEX TASK_ID_STATE_INDEX ON JOB_STATUS_TRACE_LOG (task_id(128), state)\n\nJOB_STATUS_TRACE_LOG.INSERT=INSERT INTO JOB_STATUS_TRACE_LOG (id, job_name, original_task_id, task_id, slave_id, execution_type, sharding_item, state, message, creation_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_STATUS_TRACE_LOG.SELECT=SELECT * FROM JOB_STATUS_TRACE_LOG WHERE task_id = ?\nJOB_STATUS_TRACE_LOG.SELECT_ORIGINAL_TASK_ID=SELECT * FROM (SELECT ROWNUMBER() OVER() AS ROW, A.* FROM JOB_STATUS_TRACE_LOG A WHERE A.TASK_ID = '4' AND A.STATE= 'TASK_STAGING') AS B WHERE B.ROW = 1\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/sql/GaussDB.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nJOB_EXECUTION_LOG.TABLE.CREATE=CREATE TABLE JOB_EXECUTION_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, task_id VARCHAR(255) NOT NULL, hostname VARCHAR(255) NOT NULL, ip VARCHAR(50) NOT NULL, sharding_item INT NOT NULL, execution_source VARCHAR(20) NOT NULL, failure_cause VARCHAR(4000) NULL, is_success BOOLEAN NOT NULL, start_time TIMESTAMP NULL, complete_time TIMESTAMP NULL, PRIMARY KEY (id))\n\nJOB_EXECUTION_LOG.INSERT=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_COMPLETE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time, complete_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_FAILURE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, failure_cause, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.UPDATE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ? WHERE id = ?\nJOB_EXECUTION_LOG.UPDATE_FAILURE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ?, failure_cause = ? WHERE id = ?\n\nJOB_STATUS_TRACE_LOG.TABLE.CREATE=CREATE TABLE JOB_STATUS_TRACE_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, original_task_id VARCHAR(255) NULL, task_id VARCHAR(255) NOT NULL, slave_id VARCHAR(50) NOT NULL, execution_type VARCHAR(20) NOT NULL, sharding_item VARCHAR(100) NOT NULL, state VARCHAR(20) NOT NULL, message VARCHAR(4000) NULL, creation_time TIMESTAMP NULL, PRIMARY KEY (id))\nTASK_ID_STATE_INDEX.INDEX.CREATE=CREATE INDEX TASK_ID_STATE_INDEX ON JOB_STATUS_TRACE_LOG (task_id, state)\n\nJOB_STATUS_TRACE_LOG.INSERT=INSERT INTO JOB_STATUS_TRACE_LOG (id, job_name, original_task_id, task_id, slave_id, execution_type, sharding_item,  state, message, creation_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_STATUS_TRACE_LOG.SELECT=SELECT * FROM JOB_STATUS_TRACE_LOG WHERE task_id=?\nJOB_STATUS_TRACE_LOG.SELECT_ORIGINAL_TASK_ID=SELECT original_task_id FROM JOB_STATUS_TRACE_LOG WHERE task_id=? and state='TASK_STAGING' LIMIT 1\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/sql/H2.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nJOB_EXECUTION_LOG.TABLE.CREATE=CREATE TABLE IF NOT EXISTS JOB_EXECUTION_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, task_id VARCHAR(255) NOT NULL, hostname VARCHAR(255) NOT NULL, ip VARCHAR(50) NOT NULL, sharding_item INT NOT NULL, execution_source VARCHAR(20) NOT NULL, failure_cause VARCHAR(4000) NULL, is_success INT NOT NULL, start_time TIMESTAMP NULL, complete_time TIMESTAMP NULL, PRIMARY KEY (id))\n\nJOB_EXECUTION_LOG.INSERT=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_COMPLETE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time, complete_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_FAILURE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, failure_cause, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.UPDATE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ? WHERE id = ?\nJOB_EXECUTION_LOG.UPDATE_FAILURE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ?, failure_cause = ? WHERE id = ?\n\nJOB_STATUS_TRACE_LOG.TABLE.CREATE=CREATE TABLE IF NOT EXISTS JOB_STATUS_TRACE_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, original_task_id VARCHAR(255) NOT NULL, task_id VARCHAR(255) NOT NULL, slave_id VARCHAR(50) NOT NULL, execution_type VARCHAR(20) NOT NULL, sharding_item VARCHAR(100) NOT NULL, state VARCHAR(20) NOT NULL, message VARCHAR(4000) NULL, creation_time TIMESTAMP NULL, PRIMARY KEY (id))\nTASK_ID_STATE_INDEX.INDEX.CREATE=CREATE INDEX IF NOT EXISTS TASK_ID_STATE_INDEX ON JOB_STATUS_TRACE_LOG (task_id, state)\n\nJOB_STATUS_TRACE_LOG.INSERT=INSERT INTO JOB_STATUS_TRACE_LOG (id, job_name, original_task_id, task_id, slave_id, execution_type, sharding_item, state, message, creation_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_STATUS_TRACE_LOG.SELECT=SELECT * FROM JOB_STATUS_TRACE_LOG WHERE task_id = ?\nJOB_STATUS_TRACE_LOG.SELECT_ORIGINAL_TASK_ID=SELECT original_task_id FROM JOB_STATUS_TRACE_LOG WHERE task_id = ? and state= 'TASK_STAGING' LIMIT 1\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/sql/MySQL.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nJOB_EXECUTION_LOG.TABLE.CREATE = CREATE TABLE \\\n    IF NOT EXISTS JOB_EXECUTION_LOG (   \\\n        auto_id int NOT NULL AUTO_INCREMENT,    \\\n        id VARCHAR (40) NOT NULL,               \\\n        job_name VARCHAR (100) NOT NULL,        \\\n        task_id VARCHAR (255) NOT NULL,         \\\n        hostname VARCHAR (255) NOT NULL,        \\\n        ip VARCHAR (50) NOT NULL,               \\\n        sharding_item INT NOT NULL,             \\\n        execution_source VARCHAR (20) NOT NULL, \\\n        failure_cause VARCHAR (4000) NULL,      \\\n        is_success INT NOT NULL,                \\\n        start_time TIMESTAMP NULL,              \\\n        complete_time TIMESTAMP NULL,           \\\n        PRIMARY KEY (auto_id),                  \\\n        UNIQUE KEY `id` (`id`)                  \\\n    ) ENGINE=InnoDB\n\nJOB_EXECUTION_LOG.INSERT=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_COMPLETE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time, complete_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_FAILURE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, failure_cause, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.UPDATE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ? WHERE id = ?\nJOB_EXECUTION_LOG.UPDATE_FAILURE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ?, failure_cause = ? WHERE id = ?\n\nJOB_STATUS_TRACE_LOG.TABLE.CREATE= CREATE TABLE \\\n    IF NOT EXISTS JOB_STATUS_TRACE_LOG ( \\\n        auto_id int NOT NULL AUTO_INCREMENT,     \\\n        id VARCHAR (40) NOT NULL,                \\\n        job_name VARCHAR (100) NOT NULL,         \\\n        original_task_id VARCHAR (255) NOT NULL, \\\n        task_id VARCHAR (255) NOT NULL,          \\\n        slave_id VARCHAR (50) NOT NULL,          \\\n        execution_type VARCHAR (20) NOT NULL,    \\\n        sharding_item VARCHAR (100) NOT NULL,    \\\n        state VARCHAR (20) NOT NULL,             \\\n        message VARCHAR (4000) NULL,             \\\n        creation_time TIMESTAMP NULL,            \\\n        PRIMARY KEY (auto_id)                    \\\n    ) ENGINE=InnoDB\n\nTASK_ID_STATE_INDEX.INDEX.CREATE=CREATE INDEX TASK_ID_STATE_INDEX ON JOB_STATUS_TRACE_LOG (task_id(128), state)\n\nJOB_STATUS_TRACE_LOG.INSERT=INSERT INTO JOB_STATUS_TRACE_LOG (id, job_name, original_task_id, task_id, slave_id, execution_type, sharding_item, state, message, creation_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_STATUS_TRACE_LOG.SELECT=SELECT id, job_name, original_task_id, task_id, slave_id, source, execution_type, sharding_item, state, message, creation_time FROM JOB_STATUS_TRACE_LOG WHERE task_id = ?\nJOB_STATUS_TRACE_LOG.SELECT_ORIGINAL_TASK_ID=SELECT original_task_id FROM JOB_STATUS_TRACE_LOG WHERE task_id = ? and state= 'TASK_STAGING' LIMIT 1\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/sql/Oracle.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nJOB_EXECUTION_LOG.TABLE.CREATE=CREATE TABLE JOB_EXECUTION_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, task_id VARCHAR(255) NOT NULL, hostname VARCHAR(255) NOT NULL, ip VARCHAR(50) NOT NULL, sharding_item NUMBER NOT NULL, execution_source VARCHAR(20) NOT NULL, failure_cause VARCHAR(4000) NULL, is_success NUMBER NOT NULL, start_time TIMESTAMP NULL, complete_time TIMESTAMP NULL, PRIMARY KEY (id))\n\nJOB_EXECUTION_LOG.INSERT=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_COMPLETE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time, complete_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_FAILURE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, failure_cause, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.UPDATE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ? WHERE id = ?\nJOB_EXECUTION_LOG.UPDATE_FAILURE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ?, failure_cause = ? WHERE id = ?\n\nJOB_STATUS_TRACE_LOG.TABLE.CREATE=CREATE TABLE JOB_STATUS_TRACE_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, original_task_id VARCHAR(255) NOT NULL, task_id VARCHAR(255) NOT NULL, slave_id VARCHAR(50) NOT NULL, execution_type VARCHAR(20) NOT NULL, sharding_item VARCHAR(100) NOT NULL, state VARCHAR(20) NOT NULL, message VARCHAR(4000) NULL, creation_time TIMESTAMP NULL, PRIMARY KEY (id))\nTASK_ID_STATE_INDEX.INDEX.CREATE=CREATE INDEX TASK_ID_STATE_INDEX ON JOB_STATUS_TRACE_LOG (task_id, state)\n\nJOB_STATUS_TRACE_LOG.INSERT=INSERT INTO JOB_STATUS_TRACE_LOG (id, job_name, original_task_id, task_id, slave_id, execution_type, sharding_item, state, message, creation_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_STATUS_TRACE_LOG.SELECT=SELECT * FROM JOB_STATUS_TRACE_LOG WHERE task_id = ?\nJOB_STATUS_TRACE_LOG.SELECT_ORIGINAL_TASK_ID=SELECT original_task_id FROM JOB_STATUS_TRACE_LOG WHERE task_id = ? and state= 'TASK_STAGING' and ROWNUM = 1\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/sql/PostgreSQL.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nJOB_EXECUTION_LOG.TABLE.CREATE=CREATE TABLE JOB_EXECUTION_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, task_id VARCHAR(255) NOT NULL, hostname VARCHAR(255) NOT NULL, ip VARCHAR(50) NOT NULL, sharding_item INT NOT NULL, execution_source VARCHAR(20) NOT NULL, failure_cause VARCHAR(4000) NULL, is_success BOOLEAN NOT NULL, start_time TIMESTAMP NULL, complete_time TIMESTAMP NULL, PRIMARY KEY (id))\n\nJOB_EXECUTION_LOG.INSERT=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_COMPLETE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time, complete_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_FAILURE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, failure_cause, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.UPDATE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ? WHERE id = ?\nJOB_EXECUTION_LOG.UPDATE_FAILURE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ?, failure_cause = ? WHERE id = ?\n\nJOB_STATUS_TRACE_LOG.TABLE.CREATE=CREATE TABLE JOB_STATUS_TRACE_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, original_task_id VARCHAR(255) NOT NULL, task_id VARCHAR(255) NOT NULL, slave_id VARCHAR(50) NOT NULL, execution_type VARCHAR(20) NOT NULL, sharding_item VARCHAR(100) NOT NULL, state VARCHAR(20) NOT NULL, message VARCHAR(4000) NULL, creation_time TIMESTAMP NULL, PRIMARY KEY (id))\nTASK_ID_STATE_INDEX.INDEX.CREATE=CREATE INDEX TASK_ID_STATE_INDEX ON JOB_STATUS_TRACE_LOG (task_id, state)\n\nJOB_STATUS_TRACE_LOG.INSERT=INSERT INTO JOB_STATUS_TRACE_LOG (id, job_name, original_task_id, task_id, slave_id, execution_type, sharding_item,  state, message, creation_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_STATUS_TRACE_LOG.SELECT=SELECT * FROM JOB_STATUS_TRACE_LOG WHERE task_id=?\nJOB_STATUS_TRACE_LOG.SELECT_ORIGINAL_TASK_ID=SELECT original_task_id FROM JOB_STATUS_TRACE_LOG WHERE task_id=? and state='TASK_STAGING' LIMIT 1\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/sql/SQL92.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nJOB_EXECUTION_LOG.TABLE.CREATE=CREATE TABLE JOB_EXECUTION_LOG (id CHARACTER(40) NOT NULL, job_name CHARACTER(100) NOT NULL, task_id CHARACTER(255) NOT NULL, hostname CHARACTER(255) NOT NULL, ip CHARACTER(50) NOT NULL, sharding_item INTEGER NOT NULL, execution_source CHARACTER(20) NOT NULL, failure_cause CHARACTER VARYING(4000) NULL, is_success INTEGER NOT NULL, start_time TIMESTAMP NULL, complete_time TIMESTAMP NULL, PRIMARY KEY (id))\n\nJOB_EXECUTION_LOG.INSERT=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_COMPLETE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time, complete_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_FAILURE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, failure_cause, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.UPDATE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ? WHERE id = ?\nJOB_EXECUTION_LOG.UPDATE_FAILURE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ?, failure_cause = ? WHERE id = ?\n\nJOB_STATUS_TRACE_LOG.TABLE.CREATE=CREATE TABLE JOB_STATUS_TRACE_LOG (id CHARACTER(40) NOT NULL, job_name CHARACTER(100) NOT NULL, original_task_id CHARACTER(255) NOT NULL, task_id CHARACTER(255) NOT NULL, slave_id CHARACTER(50) NOT NULL, execution_type CHARACTER(20) NOT NULL, sharding_item CHARACTER(100) NOT NULL, state CHARACTER(20) NOT NULL, message CHARACTER VARYING(4000) NULL, creation_time TIMESTAMP NULL, PRIMARY KEY (id))\nTASK_ID_STATE_INDEX.INDEX.CREATE=CREATE INDEX TASK_ID_STATE_INDEX ON JOB_STATUS_TRACE_LOG (task_id, state)\n\nJOB_STATUS_TRACE_LOG.INSERT=INSERT INTO JOB_STATUS_TRACE_LOG (id, job_name, original_task_id, task_id, slave_id, execution_type, sharding_item,  state, message, creation_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_STATUS_TRACE_LOG.SELECT=SELECT * FROM JOB_STATUS_TRACE_LOG WHERE task_id=?\nJOB_STATUS_TRACE_LOG.SELECT_ORIGINAL_TASK_ID=SELECT original_task_id FROM JOB_STATUS_TRACE_LOG WHERE task_id=? and state='TASK_STAGING' LIMIT 1\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/main/resources/META-INF/sql/SQLServer.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nJOB_EXECUTION_LOG.TABLE.CREATE=CREATE TABLE JOB_EXECUTION_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, task_id VARCHAR(255) NOT NULL, hostname VARCHAR(255) NOT NULL, ip VARCHAR(50) NOT NULL, sharding_item INT NOT NULL, execution_source VARCHAR(20) NOT NULL, failure_cause VARCHAR(4000) NULL, is_success INT NOT NULL, start_time DATETIME NULL, complete_time DATETIME NULL, PRIMARY KEY (id))\n\nJOB_EXECUTION_LOG.INSERT=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_COMPLETE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, is_success, start_time, complete_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.INSERT_FAILURE=INSERT INTO JOB_EXECUTION_LOG (id, job_name, task_id, hostname, ip, sharding_item, execution_source, failure_cause, is_success, start_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_EXECUTION_LOG.UPDATE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ? WHERE id = ?\nJOB_EXECUTION_LOG.UPDATE_FAILURE=UPDATE JOB_EXECUTION_LOG SET is_success = ?, complete_time = ?, failure_cause = ? WHERE id = ?\n\nJOB_STATUS_TRACE_LOG.TABLE.CREATE=CREATE TABLE JOB_STATUS_TRACE_LOG (id VARCHAR(40) NOT NULL, job_name VARCHAR(100) NOT NULL, original_task_id VARCHAR(255) NOT NULL, task_id VARCHAR(255) NOT NULL, slave_id VARCHAR(50) NOT NULL, execution_type VARCHAR(20) NOT NULL, sharding_item VARCHAR(100) NOT NULL, state VARCHAR(20) NOT NULL, message VARCHAR(4000) NULL, creation_time DATETIME NULL, PRIMARY KEY (id))\nTASK_ID_STATE_INDEX.INDEX.CREATE=CREATE INDEX TASK_ID_STATE_INDEX ON JOB_STATUS_TRACE_LOG (task_id, state)\n\nJOB_STATUS_TRACE_LOG.INSERT=INSERT INTO JOB_STATUS_TRACE_LOG (id, job_name, original_task_id, task_id, slave_id, execution_type, sharding_item, state, message, creation_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nJOB_STATUS_TRACE_LOG.SELECT=SELECT * FROM JOB_STATUS_TRACE_LOG WHERE task_id = ?\nJOB_STATUS_TRACE_LOG.SELECT_ORIGINAL_TASK_ID=SELECT TOP 1 original_task_id FROM JOB_STATUS_TRACE_LOG WHERE task_id = ? and state = 'TASK_STAGING'\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/test/java/org/apache/shardingsphere/elasticjob/tracing/rdb/config/RDBTracingStorageConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.config;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.junit.jupiter.api.Test;\n\nimport javax.sql.DataSource;\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.Map;\n\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.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass RDBTracingStorageConfigurationTest {\n    \n    @Test\n    void assertGetDataSourceConfiguration() throws SQLException {\n        HikariDataSource actualDataSource = new HikariDataSource();\n        actualDataSource.setDriverClassName(\"org.h2.Driver\");\n        actualDataSource.setJdbcUrl(\"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL\");\n        actualDataSource.setUsername(\"root\");\n        actualDataSource.setPassword(\"root\");\n        actualDataSource.setLoginTimeout(1);\n        RDBTracingStorageConfiguration actual = RDBTracingStorageConfiguration.getDataSourceConfiguration(actualDataSource);\n        assertThat(actual.getDataSourceClassName(), is(HikariDataSource.class.getName()));\n        assertThat(actual.getProps().get(\"driverClassName\").toString(), is(\"org.h2.Driver\"));\n        assertThat(actual.getProps().get(\"jdbcUrl\").toString(), is(\"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL\"));\n        assertThat(actual.getProps().get(\"username\").toString(), is(\"root\"));\n        assertThat(actual.getProps().get(\"password\").toString(), is(\"root\"));\n        assertNull(actual.getProps().get(\"loginTimeout\"));\n    }\n    \n    @Test\n    void assertCreateDataSource() {\n        Map<String, Object> props = new HashMap<>(16, 1);\n        props.put(\"driverClassName\", \"org.h2.Driver\");\n        props.put(\"jdbcUrl\", \"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL\");\n        props.put(\"username\", \"root\");\n        props.put(\"password\", \"root\");\n        props.put(\"loginTimeout\", \"5000\");\n        props.put(\"test\", \"test\");\n        RDBTracingStorageConfiguration dataSourceConfig = new RDBTracingStorageConfiguration(HikariDataSource.class.getName());\n        dataSourceConfig.getProps().putAll(props);\n        HikariDataSource actual = (HikariDataSource) dataSourceConfig.createDataSource();\n        assertThat(actual.getDriverClassName(), is(\"org.h2.Driver\"));\n        assertThat(actual.getJdbcUrl(), is(\"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL\"));\n        assertThat(actual.getUsername(), is(\"root\"));\n        assertThat(actual.getPassword(), is(\"root\"));\n    }\n    \n    @Test\n    void assertEquals() {\n        RDBTracingStorageConfiguration originalDataSourceConfig = new RDBTracingStorageConfiguration(HikariDataSource.class.getName());\n        RDBTracingStorageConfiguration targetDataSourceConfig = new RDBTracingStorageConfiguration(HikariDataSource.class.getName());\n        assertThat(originalDataSourceConfig, is(originalDataSourceConfig));\n        assertThat(originalDataSourceConfig, is(targetDataSourceConfig));\n        originalDataSourceConfig.getProps().put(\"username\", \"root\");\n        targetDataSourceConfig.getProps().put(\"username\", \"root\");\n        assertThat(originalDataSourceConfig, is(targetDataSourceConfig));\n    }\n    \n    @Test\n    void assertNotEquals() {\n        RDBTracingStorageConfiguration originalDataSourceConfig = new RDBTracingStorageConfiguration(HikariDataSource.class.getName());\n        RDBTracingStorageConfiguration targetDataSourceConfig = new RDBTracingStorageConfiguration(HikariDataSource.class.getName());\n        originalDataSourceConfig.getProps().put(\"username\", \"root\");\n        targetDataSourceConfig.getProps().put(\"username\", \"root0\");\n        assertThat(originalDataSourceConfig, not(targetDataSourceConfig));\n    }\n    \n    @Test\n    void assertEqualsWithNull() {\n        assertFalse(new RDBTracingStorageConfiguration(HikariDataSource.class.getName()).equals(null));\n    }\n    \n    @Test\n    void assertSameHashCode() {\n        RDBTracingStorageConfiguration originalDataSourceConfig = new RDBTracingStorageConfiguration(HikariDataSource.class.getName());\n        RDBTracingStorageConfiguration targetDataSourceConfig = new RDBTracingStorageConfiguration(HikariDataSource.class.getName());\n        assertThat(originalDataSourceConfig.hashCode(), is(targetDataSourceConfig.hashCode()));\n        originalDataSourceConfig.getProps().put(\"username\", \"root\");\n        targetDataSourceConfig.getProps().put(\"username\", \"root\");\n        assertThat(originalDataSourceConfig.hashCode(), is(targetDataSourceConfig.hashCode()));\n        originalDataSourceConfig.getProps().put(\"password\", \"root\");\n        targetDataSourceConfig.getProps().put(\"password\", \"root\");\n        assertThat(originalDataSourceConfig.hashCode(), is(targetDataSourceConfig.hashCode()));\n    }\n    \n    @Test\n    void assertDifferentHashCode() {\n        RDBTracingStorageConfiguration originalDataSourceConfig = new RDBTracingStorageConfiguration(HikariDataSource.class.getName());\n        RDBTracingStorageConfiguration targetDataSourceConfig = new RDBTracingStorageConfiguration(HikariDataSource.class.getName());\n        originalDataSourceConfig.getProps().put(\"username\", \"root\");\n        targetDataSourceConfig.getProps().put(\"username\", \"root\");\n        targetDataSourceConfig.getProps().put(\"password\", \"root\");\n        assertThat(originalDataSourceConfig.hashCode(), not(targetDataSourceConfig.hashCode()));\n        originalDataSourceConfig = new RDBTracingStorageConfiguration(HikariDataSource.class.getName());\n        targetDataSourceConfig = new RDBTracingStorageConfiguration(DataSource.class.getName());\n        assertThat(originalDataSourceConfig.hashCode(), not(targetDataSourceConfig.hashCode()));\n    }\n    \n    @Test\n    void assertGetDataSourceConfigurationWithConnectionInitSqls() {\n        HikariDataSource actualDataSource = new HikariDataSource();\n        actualDataSource.setDriverClassName(\"org.h2.Driver\");\n        actualDataSource.setJdbcUrl(\"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL\");\n        actualDataSource.setUsername(\"root\");\n        actualDataSource.setPassword(\"root\");\n        actualDataSource.setConnectionInitSql(\"set names utf8mb4;set names utf8;\");\n        RDBTracingStorageConfiguration actual = RDBTracingStorageConfiguration.getDataSourceConfiguration(actualDataSource);\n        assertThat(actual.getDataSourceClassName(), is(HikariDataSource.class.getName()));\n        assertThat(actual.getProps().get(\"driverClassName\").toString(), is(\"org.h2.Driver\"));\n        assertThat(actual.getProps().get(\"jdbcUrl\").toString(), is(\"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL\"));\n        assertThat(actual.getProps().get(\"username\").toString(), is(\"root\"));\n        assertThat(actual.getProps().get(\"password\").toString(), is(\"root\"));\n        assertNull(actual.getProps().get(\"loginTimeout\"));\n        assertThat(actual.getProps().get(\"connectionInitSql\"), is(\"set names utf8mb4;set names utf8;\"));\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/test/java/org/apache/shardingsphere/elasticjob/tracing/rdb/listener/RDBTracingListenerFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.listener;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.exception.TracingConfigurationException;\nimport org.junit.jupiter.api.Test;\n\nimport javax.sql.DataSource;\nimport java.sql.SQLException;\n\nimport static org.hamcrest.CoreMatchers.instanceOf;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass RDBTracingListenerFactoryTest {\n    \n    @Test\n    void assertCreateTracingListenerSuccess() throws TracingConfigurationException {\n        HikariDataSource dataSource = new HikariDataSource();\n        dataSource.setDriverClassName(org.h2.Driver.class.getName());\n        dataSource.setJdbcUrl(\"jdbc:h2:mem:job_event_storage\");\n        dataSource.setUsername(\"sa\");\n        dataSource.setPassword(\"\");\n        assertThat(new RDBTracingListenerFactory().create(dataSource), instanceOf(RDBTracingListener.class));\n    }\n    \n    @Test\n    void assertCreateTracingListenerFailure() throws SQLException {\n        DataSource dataSource = mock(DataSource.class);\n        when(dataSource.getConnection()).thenThrow(new SQLException());\n        assertThrows(TracingConfigurationException.class, () -> new RDBTracingListenerFactory().create(dataSource));\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/test/java/org/apache/shardingsphere/elasticjob/tracing/rdb/listener/RDBTracingListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.listener;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.event.JobTracingEventBus;\nimport org.apache.shardingsphere.elasticjob.spi.executor.ExecutionType;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent.State;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport javax.sql.DataSource;\nimport java.sql.SQLException;\n\nimport static org.mockito.Mockito.atMost;\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass RDBTracingListenerTest {\n    \n    private static final String JOB_NAME = \"test_rdb_event_listener\";\n    \n    @Mock\n    private RDBJobEventRepository repository;\n    \n    private JobTracingEventBus jobTracingEventBus;\n    \n    @BeforeEach\n    void setUp() throws SQLException {\n        HikariDataSource dataSource = new HikariDataSource();\n        dataSource.setDriverClassName(org.h2.Driver.class.getName());\n        dataSource.setJdbcUrl(\"jdbc:h2:mem:job_event_storage\");\n        dataSource.setUsername(\"sa\");\n        dataSource.setPassword(\"\");\n        RDBTracingListener tracingListener = new RDBTracingListener(dataSource);\n        ReflectionUtils.setFieldValue(tracingListener, \"repository\", repository);\n        jobTracingEventBus = new JobTracingEventBus(new TracingConfiguration<DataSource>(\"RDB\", dataSource));\n    }\n    \n    @Test\n    void assertPostJobExecutionEvent() {\n        JobExecutionEvent jobExecutionEvent = new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", JOB_NAME, JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);\n        jobTracingEventBus.post(jobExecutionEvent);\n        verify(repository, atMost(1)).addJobExecutionEvent(jobExecutionEvent);\n    }\n    \n    @Test\n    void assertPostJobStatusTraceEvent() {\n        JobStatusTraceEvent jobStatusTraceEvent = new JobStatusTraceEvent(JOB_NAME, \"fake_task_id\", \"fake_slave_id\", ExecutionType.READY, \"0\", State.TASK_RUNNING, \"message is empty.\");\n        jobTracingEventBus.post(jobStatusTraceEvent);\n        verify(repository, atMost(1)).addJobStatusTraceEvent(jobStatusTraceEvent);\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/test/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/converter/RDBTracingStorageConfigurationConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.converter;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.exception.TracingStorageUnavailableException;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfigurationConverter;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.storage.TracingStorageConverterFactory;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.SQLException;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass RDBTracingStorageConfigurationConverterTest {\n    \n    @Mock\n    private DataSource dataSource;\n    \n    @Mock\n    private Connection connection;\n    \n    @Mock\n    private DatabaseMetaData databaseMetaData;\n    \n    @Test\n    void assertConvert() throws SQLException {\n        when(dataSource.getConnection()).thenReturn(connection);\n        when(connection.getMetaData()).thenReturn(databaseMetaData);\n        when(databaseMetaData.getURL()).thenReturn(\"jdbc:url\");\n        RDBTracingStorageConfigurationConverter converter = new RDBTracingStorageConfigurationConverter();\n        assertNotNull(converter.toConfiguration(dataSource));\n    }\n    \n    @Test\n    void assertConvertFailed() {\n        assertThrows(TracingStorageUnavailableException.class, () -> {\n            RDBTracingStorageConfigurationConverter converter = new RDBTracingStorageConfigurationConverter();\n            doThrow(SQLException.class).when(dataSource).getConnection();\n            converter.toConfiguration(dataSource);\n        });\n    }\n    \n    @Test\n    void assertStorageType() {\n        TracingStorageConfigurationConverter<HikariDataSource> converter = TracingStorageConverterFactory.findConverter(HikariDataSource.class).orElse(null);\n        assertNotNull(converter);\n        assertThat(converter.storageType(), is(DataSource.class));\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/test/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/datasource/DataSourceRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.datasource;\n\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.config.RDBTracingStorageConfiguration;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport javax.sql.DataSource;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.not;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass DataSourceRegistryTest {\n    \n    @Mock\n    private RDBTracingStorageConfiguration dataSourceConfig;\n    \n    @Test\n    void assertGetDataSourceBySameConfiguration() {\n        when(dataSourceConfig.createDataSource()).then(invocation -> mock(DataSource.class));\n        DataSource expected = DataSourceRegistry.getInstance().getDataSource(dataSourceConfig);\n        DataSource actual = DataSourceRegistry.getInstance().getDataSource(dataSourceConfig);\n        verify(dataSourceConfig).createDataSource();\n        assertThat(actual, is(expected));\n    }\n    \n    @Test\n    void assertGetDataSourceWithDifferentConfiguration() {\n        when(dataSourceConfig.createDataSource()).then(invocation -> mock(DataSource.class));\n        RDBTracingStorageConfiguration anotherDataSourceConfig = mock(RDBTracingStorageConfiguration.class);\n        when(anotherDataSourceConfig.createDataSource()).then(invocation -> mock(DataSource.class));\n        DataSource one = DataSourceRegistry.getInstance().getDataSource(dataSourceConfig);\n        DataSource another = DataSourceRegistry.getInstance().getDataSource(anotherDataSourceConfig);\n        verify(dataSourceConfig).createDataSource();\n        verify(anotherDataSourceConfig).createDataSource();\n        assertThat(another, not(one));\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/test/java/org/apache/shardingsphere/elasticjob/tracing/rdb/storage/repository/RDBJobEventRepositoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.shardingsphere.elasticjob.spi.executor.ExecutionType;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent.State;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport java.sql.SQLException;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.startsWith;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass RDBJobEventRepositoryTest {\n    \n    private RDBJobEventRepository repository;\n    \n    private HikariDataSource dataSource;\n    \n    @BeforeEach\n    void setup() throws SQLException {\n        dataSource = new HikariDataSource();\n        dataSource.setDriverClassName(org.h2.Driver.class.getName());\n        dataSource.setJdbcUrl(\"jdbc:h2:mem:job_event_storage\");\n        dataSource.setUsername(\"sa\");\n        dataSource.setPassword(\"\");\n        repository = RDBJobEventRepository.getInstance(dataSource);\n    }\n    \n    @AfterEach\n    void tearDown() {\n        dataSource.close();\n    }\n    \n    @Test\n    void assertAddJobExecutionEvent() {\n        assertTrue(repository.addJobExecutionEvent(new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0)));\n    }\n    \n    @Test\n    void assertAddJobStatusTraceEvent() {\n        assertTrue(repository.addJobStatusTraceEvent(\n                new JobStatusTraceEvent(\"test_job\", \"fake_task_id\", \"fake_slave_id\", ExecutionType.READY, \"0\", State.TASK_RUNNING, \"message is empty.\")));\n    }\n    \n    @Test\n    void assertUpdateJobExecutionEventWhenSuccess() {\n        JobExecutionEvent startEvent = new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);\n        assertTrue(repository.addJobExecutionEvent(startEvent));\n        JobExecutionEvent successEvent = startEvent.executionSuccess();\n        assertTrue(repository.addJobExecutionEvent(successEvent));\n    }\n    \n    @Test\n    void assertUpdateJobExecutionEventWhenFailure() {\n        JobExecutionEvent startEvent = new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);\n        assertTrue(repository.addJobExecutionEvent(startEvent));\n        JobExecutionEvent failureEvent = startEvent.executionFailure(\"java.lang.RuntimeException: failure\");\n        assertTrue(repository.addJobExecutionEvent(failureEvent));\n        assertThat(failureEvent.getFailureCause(), is(\"java.lang.RuntimeException: failure\"));\n        assertNotNull(failureEvent.getCompleteTime());\n    }\n    \n    @Test\n    void assertUpdateJobExecutionEventWhenSuccessAndConflict() {\n        JobExecutionEvent startEvent = new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);\n        JobExecutionEvent successEvent = startEvent.executionSuccess();\n        assertTrue(repository.addJobExecutionEvent(successEvent));\n        assertFalse(repository.addJobExecutionEvent(startEvent));\n    }\n    \n    @Test\n    void assertUpdateJobExecutionEventWhenFailureAndConflict() {\n        JobExecutionEvent startEvent = new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);\n        JobExecutionEvent failureEvent = startEvent.executionFailure(\"java.lang.RuntimeException: failure\");\n        assertTrue(repository.addJobExecutionEvent(failureEvent));\n        assertThat(failureEvent.getFailureCause(), is(\"java.lang.RuntimeException: failure\"));\n        assertFalse(repository.addJobExecutionEvent(startEvent));\n    }\n    \n    @Test\n    void assertUpdateJobExecutionEventWhenFailureAndMessageExceed() {\n        JobExecutionEvent startEvent = new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);\n        assertTrue(repository.addJobExecutionEvent(startEvent));\n        StringBuilder failureMsg = new StringBuilder();\n        for (int i = 0; i < 600; i++) {\n            failureMsg.append(i);\n        }\n        JobExecutionEvent failEvent = startEvent.executionFailure(\"java.lang.RuntimeException: failure\" + failureMsg);\n        assertTrue(repository.addJobExecutionEvent(failEvent));\n        assertThat(failEvent.getFailureCause(), startsWith(\"java.lang.RuntimeException: failure\"));\n    }\n    \n    @Test\n    void assertFindJobExecutionEvent() {\n        repository.addJobExecutionEvent(new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0));\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/test/java/org/apache/shardingsphere/elasticjob/tracing/rdb/yaml/YamlRDBTracingStorageConfigurationConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.tracing.rdb.yaml;\n\nimport org.apache.shardingsphere.elasticjob.tracing.rdb.config.RDBTracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingStorageConfiguration;\nimport org.junit.jupiter.api.Test;\n\nimport javax.sql.DataSource;\nimport java.util.Collections;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass YamlRDBTracingStorageConfigurationConverterTest {\n    \n    @Test\n    void assertConvertDataSourceConfiguration() {\n        RDBTracingStorageConfiguration dataSourceConfig = new RDBTracingStorageConfiguration(\"org.h2.Driver\");\n        dataSourceConfig.getProps().put(\"foo\", \"bar\");\n        YamlDataSourceConfigurationConverter converter = new YamlDataSourceConfigurationConverter();\n        YamlTracingStorageConfiguration<DataSource> actual = converter.convertToYamlConfiguration(dataSourceConfig);\n        assertTrue(actual instanceof YamlDataSourceConfiguration);\n        YamlDataSourceConfiguration result = (YamlDataSourceConfiguration) actual;\n        assertThat(result.getDataSourceClassName(), is(\"org.h2.Driver\"));\n        assertThat(result.getProps(), is(Collections.singletonMap(\"foo\", \"bar\")));\n    }\n}\n"
  },
  {
    "path": "ecosystem/tracing/rdb/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n            <level>ERROR</level>\n        </filter>\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.converter.RDBTracingStorageConfigurationConverter\" level=\"OFF\" />\n</configuration>\n"
  },
  {
    "path": "examples/README.md",
    "content": "# ElasticJob Example\n\nElasticJob 3.x example.\n\nExample for 1.x and 2.x please see tags in `https://github.com/elasticjob/elastic-job/tree/${tag}/elastic-job-example`\n"
  },
  {
    "path": "examples/elasticjob-example-embed-zk/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-example</artifactId>\n        <version>${revision}</version>\n    </parent>\n    <artifactId>elasticjob-example-embed-zk</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-test</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "examples/elasticjob-example-embed-zk/src/main/java/org/apache/shardingsphere/elasticjob/example/EmbedZookeeperServer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example;\n\nimport org.apache.curator.test.TestingServer;\n\nimport java.io.File;\nimport java.io.IOException;\n\n/**\n * Embed ZooKeeper.\n * \n * <p>\n *     Only used for examples\n * </p>\n */\npublic final class EmbedZookeeperServer {\n    \n    private static TestingServer testingServer;\n    \n    /**\n     * Embed ZooKeeper.\n     * \n     * @param port ZooKeeper port\n     */\n    public static void start(final int port) {\n        try {\n            testingServer = new TestingServer(port, new File(String.format(\"target/test_zk_data/%s/\", System.nanoTime())));\n        // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n        // CHECKSTYLE:ON\n            ex.printStackTrace();\n        } finally {\n            Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n                try {\n                    Thread.sleep(1000L);\n                    testingServer.close();\n                } catch (final InterruptedException | IOException ignore) {\n                }\n            }));\n        }\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-java/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-example</artifactId>\n        <version>${revision}</version>\n    </parent>\n    <artifactId>elasticjob-example-java</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-wechat</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-email</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-example-jobs</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-example-embed-zk</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-bootstrap</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>jcl-over-slf4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>log4j-over-slf4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.mysql</groupId>\n            <artifactId>mysql-connector-j</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "examples/elasticjob-example-java/src/main/java/org/apache/shardingsphere/elasticjob/example/JavaMain.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.dataflow.props.DataflowJobProperties;\nimport org.apache.shardingsphere.elasticjob.error.handler.dingtalk.DingtalkPropertiesConstants;\nimport org.apache.shardingsphere.elasticjob.error.handler.email.EmailPropertiesConstants;\nimport org.apache.shardingsphere.elasticjob.error.handler.wechat.WechatPropertiesConstants;\nimport org.apache.shardingsphere.elasticjob.example.job.dataflow.JavaDataflowJob;\nimport org.apache.shardingsphere.elasticjob.example.job.simple.JavaOccurErrorJob;\nimport org.apache.shardingsphere.elasticjob.example.job.simple.JavaSimpleJob;\nimport org.apache.shardingsphere.elasticjob.http.props.HttpJobProperties;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.script.props.ScriptJobProperties;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.attribute.PosixFilePermissions;\n\npublic final class JavaMain {\n    \n    private static final int EMBED_ZOOKEEPER_PORT = 4181;\n    \n    private static final String ZOOKEEPER_CONNECTION_STRING = \"localhost:\" + EMBED_ZOOKEEPER_PORT;\n    \n    private static final String JOB_NAMESPACE = \"elasticjob-example-java\";\n    \n    // switch to MySQL by yourself\n//    private static final String EVENT_RDB_STORAGE_DRIVER = \"com.mysql.cj.jdbc.Driver\";\n//    private static final String EVENT_RDB_STORAGE_URL = \"jdbc:mysql://localhost:3306/elastic_job_log\";\n    \n    private static final String EVENT_RDB_STORAGE_DRIVER = \"org.h2.Driver\";\n    \n    private static final String EVENT_RDB_STORAGE_URL = \"jdbc:h2:mem:job_event_storage\";\n    \n    private static final String EVENT_RDB_STORAGE_USERNAME = \"sa\";\n    \n    private static final String EVENT_RDB_STORAGE_PASSWORD = \"\";\n    \n    // CHECKSTYLE:OFF\n    public static void main(final String[] args) throws IOException {\n    // CHECKSTYLE:ON\n        EmbedZookeeperServer.start(EMBED_ZOOKEEPER_PORT);\n        CoordinatorRegistryCenter regCenter = setUpRegistryCenter();\n        TracingConfiguration<DataSource> tracingConfig = new TracingConfiguration<>(\"RDB\", setUpEventTraceDataSource());\n        setUpHttpJob(regCenter, tracingConfig);\n        setUpSimpleJob(regCenter, tracingConfig);\n        setUpDataflowJob(regCenter, tracingConfig);\n        setUpScriptJob(regCenter, tracingConfig);\n        setUpOneOffJob(regCenter, tracingConfig);\n//        setUpOneOffJobWithEmail(regCenter, tracingConfig);\n//        setUpOneOffJobWithDingtalk(regCenter, tracingConfig);\n//        setUpOneOffJobWithWechat(regCenter, tracingConfig);\n    }\n    \n    private static CoordinatorRegistryCenter setUpRegistryCenter() {\n        ZookeeperConfiguration zkConfig = new ZookeeperConfiguration(ZOOKEEPER_CONNECTION_STRING, JOB_NAMESPACE);\n        CoordinatorRegistryCenter result = new ZookeeperRegistryCenter(zkConfig);\n        result.init();\n        return result;\n    }\n    \n    private static DataSource setUpEventTraceDataSource() {\n        HikariDataSource result = new HikariDataSource();\n        result.setDriverClassName(EVENT_RDB_STORAGE_DRIVER);\n        result.setJdbcUrl(EVENT_RDB_STORAGE_URL);\n        result.setUsername(EVENT_RDB_STORAGE_USERNAME);\n        result.setPassword(EVENT_RDB_STORAGE_PASSWORD);\n        return result;\n    }\n    \n    private static void setUpHttpJob(final CoordinatorRegistryCenter regCenter, final TracingConfiguration<DataSource> tracingConfig) {\n        new ScheduleJobBootstrap(regCenter, \"HTTP\", JobConfiguration.newBuilder(\"javaHttpJob\", 3)\n                .setProperty(HttpJobProperties.URI_KEY, \"https://github.com\")\n                .setProperty(HttpJobProperties.METHOD_KEY, \"GET\")\n                .cron(\"0/5 * * * * ?\").shardingItemParameters(\"0=Beijing,1=Shanghai,2=Guangzhou\").addExtraConfigurations(tracingConfig).build()).schedule();\n        \n    }\n    \n    private static void setUpSimpleJob(final CoordinatorRegistryCenter regCenter, final TracingConfiguration<DataSource> tracingConfig) {\n        new ScheduleJobBootstrap(regCenter, new JavaSimpleJob(), JobConfiguration.newBuilder(\"javaSimpleJob\", 3)\n                .cron(\"0/5 * * * * ?\").shardingItemParameters(\"0=Beijing,1=Shanghai,2=Guangzhou\").addExtraConfigurations(tracingConfig).build()).schedule();\n    }\n    \n    private static void setUpDataflowJob(final CoordinatorRegistryCenter regCenter, final TracingConfiguration<DataSource> tracingConfig) {\n        new ScheduleJobBootstrap(regCenter, new JavaDataflowJob(), JobConfiguration.newBuilder(\"javaDataflowElasticJob\", 3)\n                .cron(\"0/5 * * * * ?\").shardingItemParameters(\"0=Beijing,1=Shanghai,2=Guangzhou\")\n                .setProperty(DataflowJobProperties.STREAM_PROCESS_KEY, Boolean.TRUE.toString()).addExtraConfigurations(tracingConfig).build()).schedule();\n    }\n\n    private static void setUpOneOffJob(final CoordinatorRegistryCenter regCenter, final TracingConfiguration<DataSource> tracingConfig) {\n        new OneOffJobBootstrap(regCenter, new JavaSimpleJob(), JobConfiguration.newBuilder(\"javaOneOffSimpleJob\", 3)\n                .shardingItemParameters(\"0=Beijing,1=Shanghai,2=Guangzhou\").addExtraConfigurations(tracingConfig).build()).execute();\n    }\n    \n    private static void setUpScriptJob(final CoordinatorRegistryCenter regCenter, final TracingConfiguration<DataSource> tracingConfig) throws IOException {\n        new ScheduleJobBootstrap(regCenter, \"SCRIPT\", JobConfiguration.newBuilder(\"scriptElasticJob\", 3)\n                .cron(\"0/5 * * * * ?\").setProperty(ScriptJobProperties.SCRIPT_KEY, buildScriptCommandLine()).addExtraConfigurations(tracingConfig).build()).schedule();\n    }\n    \n    private static void setUpOneOffJobWithEmail(final CoordinatorRegistryCenter regCenter, final TracingConfiguration<DataSource> tracingConfig) {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"javaOccurErrorOfEmailJob\", 3)\n                .shardingItemParameters(\"0=Beijing,1=Shanghai,2=Guangzhou\").jobErrorHandlerType(\"EMAIL\").addExtraConfigurations(tracingConfig).build();\n        setEmailProperties(jobConfig);\n        new OneOffJobBootstrap(regCenter, new JavaOccurErrorJob(), jobConfig).execute();\n    }\n    \n    private static void setUpOneOffJobWithDingtalk(final CoordinatorRegistryCenter regCenter, final TracingConfiguration<DataSource> tracingConfig) {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"javaOccurErrorOfDingtalkJob\", 3)\n                .shardingItemParameters(\"0=Beijing,1=Shanghai,2=Guangzhou\").jobErrorHandlerType(\"DINGTALK\").addExtraConfigurations(tracingConfig).build();\n        setDingtalkProperties(jobConfig);\n        new OneOffJobBootstrap(regCenter, new JavaOccurErrorJob(), jobConfig).execute();\n    }\n    \n    private static void setUpOneOffJobWithWechat(final CoordinatorRegistryCenter regCenter, final TracingConfiguration<DataSource> tracingConfig) {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"javaOccurErrorOfWechatJob\", 3)\n                .shardingItemParameters(\"0=Beijing,1=Shanghai,2=Guangzhou\").jobErrorHandlerType(\"WECHAT\").addExtraConfigurations(tracingConfig).build();\n        setWechatProperties(jobConfig);\n        new OneOffJobBootstrap(regCenter, new JavaOccurErrorJob(), jobConfig).execute();\n    }\n    \n    private static void setEmailProperties(final JobConfiguration jobConfig) {\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.HOST, \"host\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.PORT, \"465\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.USERNAME, \"username\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.PASSWORD, \"password\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.FROM, \"from@xxx.xx\");\n        jobConfig.getProps().setProperty(EmailPropertiesConstants.TO, \"to1@xxx.xx,to1@xxx.xx\");\n    }\n    \n    private static void setDingtalkProperties(final JobConfiguration jobConfig) {\n        jobConfig.getProps().setProperty(DingtalkPropertiesConstants.WEBHOOK, \"https://oapi.dingtalk.com/robot/send?access_token=token\");\n        jobConfig.getProps().setProperty(DingtalkPropertiesConstants.KEYWORD, \"keyword\");\n        jobConfig.getProps().setProperty(DingtalkPropertiesConstants.SECRET, \"secret\");\n    }\n    \n    private static void setWechatProperties(final JobConfiguration jobConfig) {\n        jobConfig.getProps().setProperty(WechatPropertiesConstants.WEBHOOK, \"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=key\");\n    }\n    \n    private static String buildScriptCommandLine() throws IOException {\n        if (System.getProperties().getProperty(\"os.name\").contains(\"Windows\")) {\n            return Paths.get(JavaMain.class.getResource(\"/script/demo.bat\").getPath().substring(1)).toString();\n        }\n        Path result = Paths.get(JavaMain.class.getResource(\"/script/demo.sh\").getPath());\n        Files.setPosixFilePermissions(result, PosixFilePermissions.fromString(\"rwxr-xr-x\"));\n        return result.toString();\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-java/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    \n    <property name=\"log.context.name\" value=\"elasticjob-example\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <level value=\"INFO\" />\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.zookeeper\" level=\"WARN\" />\n    <logger name=\"org.apache.curator\" level=\"WARN\" />\n</configuration>\n"
  },
  {
    "path": "examples/elasticjob-example-java/src/main/resources/script/demo.bat",
    "content": "@rem\n@rem Licensed to the Apache Software Foundation (ASF) under one or more\n@rem contributor license agreements.  See the NOTICE file distributed with\n@rem this work for additional information regarding copyright ownership.\n@rem The ASF licenses this file to You under the Apache License, Version 2.0\n@rem (the \"License\"); you may not use this file except in compliance with\n@rem the License.  You may obtain a copy of the License at\n@rem\n@rem     http://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n\n@echo Sharding Context: %*\n"
  },
  {
    "path": "examples/elasticjob-example-java/src/main/resources/script/demo.sh",
    "content": "#!/bin/bash\n#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\necho Sharding Context: $*\n"
  },
  {
    "path": "examples/elasticjob-example-jobs/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-example</artifactId>\n        <version>${revision}</version>\n    </parent>\n    <artifactId>elasticjob-example-jobs</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-bootstrap</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "examples/elasticjob-example-jobs/src/main/java/org/apache/shardingsphere/elasticjob/example/fixture/entity/Foo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.fixture.entity;\n\nimport java.io.Serializable;\n\npublic final class Foo implements Serializable {\n    \n    private static final long serialVersionUID = 2706842871078949451L;\n    \n    private final long id;\n    \n    private final String location;\n    \n    private Status status;\n    \n    public Foo(final long id, final String location, final Status status) {\n        this.id = id;\n        this.location = location;\n        this.status = status;\n    }\n    \n    public long getId() {\n        return id;\n    }\n    \n    public String getLocation() {\n        return location;\n    }\n    \n    public Status getStatus() {\n        return status;\n    }\n    \n    public void setStatus(final Status status) {\n        this.status = status;\n    }\n    \n    public String toString() {\n        return String.format(\"id: %s, location: %s, status: %s\", id, location, status);\n    }\n    \n    public enum Status {\n        TODO,\n        COMPLETED\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-jobs/src/main/java/org/apache/shardingsphere/elasticjob/example/fixture/repository/FooRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.fixture.repository;\n\nimport org.apache.shardingsphere.elasticjob.example.fixture.entity.Foo;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n@Repository\npublic class FooRepository {\n    \n    private final Map<Long, Foo> data = new ConcurrentHashMap<>(300, 1);\n    \n    public FooRepository() {\n        init();\n    }\n    \n    private void init() {\n        addData(0L, 100L, \"Beijing\");\n        addData(100L, 200L, \"Shanghai\");\n        addData(200L, 300L, \"Guangzhou\");\n    }\n    \n    private void addData(final long idFrom, final long idTo, final String location) {\n        for (long i = idFrom; i < idTo; i++) {\n            data.put(i, new Foo(i, location, Foo.Status.TODO));\n        }\n    }\n    \n    public List<Foo> findTodoData(final String location, final int limit) {\n        List<Foo> result = new ArrayList<>(limit);\n        int count = 0;\n        for (Map.Entry<Long, Foo> each : data.entrySet()) {\n            Foo foo = each.getValue();\n            if (foo.getLocation().equals(location) && foo.getStatus() == Foo.Status.TODO) {\n                result.add(foo);\n                count++;\n                if (count == limit) {\n                    break;\n                }\n            }\n        }\n        return result;\n    }\n    \n    public void setCompleted(final long id) {\n        data.get(id).setStatus(Foo.Status.COMPLETED);\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-jobs/src/main/java/org/apache/shardingsphere/elasticjob/example/fixture/repository/FooRepositoryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.fixture.repository;\n\npublic final class FooRepositoryFactory {\n    \n    private static FooRepository fooRepository = new FooRepository();\n    \n    public static FooRepository getFooRepository() {\n        return fooRepository;\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-jobs/src/main/java/org/apache/shardingsphere/elasticjob/example/job/dataflow/JavaDataflowJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.job.dataflow;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob;\nimport org.apache.shardingsphere.elasticjob.example.fixture.entity.Foo;\nimport org.apache.shardingsphere.elasticjob.example.fixture.repository.FooRepository;\nimport org.apache.shardingsphere.elasticjob.example.fixture.repository.FooRepositoryFactory;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\npublic class JavaDataflowJob implements DataflowJob<Foo> {\n    \n    private final FooRepository fooRepository = FooRepositoryFactory.getFooRepository();\n    \n    @Override\n    public List<Foo> fetchData(final ShardingContext shardingContext) {\n        System.out.printf(\"Item: %s | Time: %s | Thread: %s | %s%n\",\n                shardingContext.getShardingItem(), new SimpleDateFormat(\"HH:mm:ss\").format(new Date()), Thread.currentThread().getId(), \"DATAFLOW FETCH\");\n        return fooRepository.findTodoData(shardingContext.getShardingParameter(), 10);\n    }\n    \n    @Override\n    public void processData(final ShardingContext shardingContext, final List<Foo> data) {\n        System.out.printf(\"Item: %s | Time: %s | Thread: %s | %s%n\",\n                shardingContext.getShardingItem(), new SimpleDateFormat(\"HH:mm:ss\").format(new Date()), Thread.currentThread().getId(), \"DATAFLOW PROCESS\");\n        for (Foo each : data) {\n            fooRepository.setCompleted(each.getId());\n        }\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-jobs/src/main/java/org/apache/shardingsphere/elasticjob/example/job/dataflow/SpringDataflowJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.job.dataflow;\n\nimport org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob;\nimport org.apache.shardingsphere.elasticjob.example.fixture.entity.Foo;\nimport org.apache.shardingsphere.elasticjob.example.fixture.repository.FooRepository;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\npublic class SpringDataflowJob implements DataflowJob<Foo> {\n    \n    @Autowired\n    private FooRepository fooRepository;\n    \n    @Override\n    public List<Foo> fetchData(final ShardingContext shardingContext) {\n        System.out.printf(\"Item: %s | Time: %s | Thread: %s | %s%n\",\n                shardingContext.getShardingItem(), new SimpleDateFormat(\"HH:mm:ss\").format(new Date()), Thread.currentThread().getId(), \"DATAFLOW FETCH\");\n        return fooRepository.findTodoData(shardingContext.getShardingParameter(), 10);\n    }\n    \n    @Override\n    public void processData(final ShardingContext shardingContext, final List<Foo> data) {\n        System.out.printf(\"Item: %s | Time: %s | Thread: %s | %s%n\",\n                shardingContext.getShardingItem(), new SimpleDateFormat(\"HH:mm:ss\").format(new Date()), Thread.currentThread().getId(), \"DATAFLOW PROCESS\");\n        for (Foo each : data) {\n            fooRepository.setCompleted(each.getId());\n        }\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-jobs/src/main/java/org/apache/shardingsphere/elasticjob/example/job/simple/JavaOccurErrorJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.job.simple;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\n\npublic final class JavaOccurErrorJob implements SimpleJob {\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        throw new RuntimeException(String.format(\"An exception has occurred in Job, The parameter is %s\", shardingContext.getShardingParameter()));\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-jobs/src/main/java/org/apache/shardingsphere/elasticjob/example/job/simple/JavaSimpleJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.job.simple;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.apache.shardingsphere.elasticjob.example.fixture.entity.Foo;\nimport org.apache.shardingsphere.elasticjob.example.fixture.repository.FooRepository;\nimport org.apache.shardingsphere.elasticjob.example.fixture.repository.FooRepositoryFactory;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\npublic class JavaSimpleJob implements SimpleJob {\n    \n    private final FooRepository fooRepository = FooRepositoryFactory.getFooRepository();\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        System.out.printf(\"Item: %s | Time: %s | Thread: %s | %s%n\",\n                shardingContext.getShardingItem(), new SimpleDateFormat(\"HH:mm:ss\").format(new Date()), Thread.currentThread().getId(), \"SIMPLE\");\n        List<Foo> data = fooRepository.findTodoData(shardingContext.getShardingParameter(), 10);\n        for (Foo each : data) {\n            fooRepository.setCompleted(each.getId());\n        }\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-jobs/src/main/java/org/apache/shardingsphere/elasticjob/example/job/simple/SpringSimpleJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.job.simple;\n\nimport org.apache.shardingsphere.elasticjob.example.fixture.entity.Foo;\nimport org.apache.shardingsphere.elasticjob.example.fixture.repository.FooRepository;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\npublic class SpringSimpleJob implements SimpleJob {\n    \n    @Autowired\n    private FooRepository fooRepository;\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        System.out.printf(\"Item: %s | Time: %s | Thread: %s | %s%n\",\n                shardingContext.getShardingItem(), new SimpleDateFormat(\"HH:mm:ss\").format(new Date()), Thread.currentThread().getId(), \"SIMPLE\");\n        List<Foo> data = fooRepository.findTodoData(shardingContext.getShardingParameter(), 10);\n        for (Foo each : data) {\n            fooRepository.setCompleted(each.getId());\n        }\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-spring/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-example</artifactId>\n        <version>${revision}</version>\n    </parent>\n    <artifactId>elasticjob-example-spring</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-example-jobs</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-example-embed-zk</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-wechat</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-email</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-spring-namespace</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>jcl-over-slf4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>log4j-over-slf4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.mysql</groupId>\n            <artifactId>mysql-connector-j</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "examples/elasticjob-example-spring/src/main/java/org/apache/shardingsphere/elasticjob/example/SpringMain.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example;\n\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\npublic final class SpringMain {\n    \n    private static final int EMBED_ZOOKEEPER_PORT = 5181;\n    \n    // CHECKSTYLE:OFF\n    public static void main(final String[] args) {\n    // CHECKSTYLE:ON\n        EmbedZookeeperServer.start(EMBED_ZOOKEEPER_PORT);\n        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(\"classpath:META-INF/application-context.xml\");\n        // One-off Job\n        //OneOffJobBootstrap oneOffJobBootstrap = context.getBean(\"oneOffJobBean\", OneOffJobBootstrap.class);\n        //oneOffJobBootstrap.execute();\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-spring/src/main/resources/META-INF/application-context.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://www.springframework.org/schema/context \n                        http://www.springframework.org/schema/context/spring-context.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <context:component-scan base-package=\"org.apache.shardingsphere.elasticjob.example\" />\n    <context:property-placeholder location=\"classpath:conf/*.properties\"/>\n    \n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"${serverLists}\" namespace=\"${namespace}\"\n                          base-sleep-time-milliseconds=\"${baseSleepTimeMilliseconds}\"\n                          max-sleep-time-milliseconds=\"${maxSleepTimeMilliseconds}\" max-retries=\"${maxRetries}\" />\n    \n    <elasticjob:snapshot id=\"jobSnapshot\" registry-center-ref=\"regCenter\" dump-port=\"9999\" />\n    \n    <bean id=\"elasticJobTracingDataSource\" class=\"com.zaxxer.hikari.HikariDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"${event.rdb.driver}\" />\n        <property name=\"jdbcUrl\" value=\"${event.rdb.url}\" />\n        <property name=\"username\" value=\"${event.rdb.username}\" />\n        <property name=\"password\" value=\"${event.rdb.password}\" />\n    </bean>\n\n    <elasticjob:rdb-tracing id=\"elasticJobTrace\" data-source-ref=\"elasticJobTracingDataSource\" />\n\n    <bean id=\"simpleJob\" class=\"org.apache.shardingsphere.elasticjob.example.job.simple.SpringSimpleJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.example.job.dataflow.SpringDataflowJob\" />\n\n    <elasticjob:job id=\"${simple.id}\" job-ref=\"simpleJob\" registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\"\n                    sharding-total-count=\"${simple.shardingTotalCount}\" cron=\"${simple.cron}\"\n                    sharding-item-parameters=\"${simple.shardingItemParameters}\"\n                    monitor-execution=\"${simple.monitorExecution}\" failover=\"${simple.failover}\"\n                    description=\"${simple.description}\"\n                    disabled=\"${simple.disabled}\" overwrite=\"${simple.overwrite}\" />\n\n    <elasticjob:job id=\"${dataflow.id}\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\"\n                    sharding-total-count=\"${dataflow.shardingTotalCount}\" cron=\"${dataflow.cron}\"\n                    sharding-item-parameters=\"${dataflow.shardingItemParameters}\"\n                    monitor-execution=\"${dataflow.monitorExecution}\" failover=\"${dataflow.failover}\"\n                    max-time-diff-seconds=\"${dataflow.maxTimeDiffSeconds}\" description=\"${dataflow.description}\"\n                    disabled=\"${dataflow.disabled}\" overwrite=\"${dataflow.overwrite}\">\n        <props>\n            <prop key=\"streaming.process\">${dataflow.streamingProcess}</prop>\n        </props>\n    </elasticjob:job>\n\n\n    <!-- use One-off job-->\n<!--    <bean id=\"oneOffJob\" class=\"org.apache.shardingsphere.elasticjob.kernel.example.job.simple.SpringSimpleJob\" />-->\n<!--    <elasticjob:job id=\"oneOffJobBean\" job-ref=\"oneOffJob\" registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\"-->\n<!--      sharding-total-count=\"${simple.shardingTotalCount}\"-->\n<!--      sharding-item-parameters=\"${simple.shardingItemParameters}\"-->\n<!--      monitor-execution=\"${simple.monitorExecution}\"-->\n<!--      failover=\"${simple.failover}\"-->\n<!--      description=\"${simple.description}\"-->\n<!--      disabled=\"${simple.disabled}\" overwrite=\"${simple.overwrite}\" />-->\n\n    <!-- use absolute path to run script job -->\n    <!--<elasticjob:job id=\"${script.id}\" registry-center-ref=\"regCenter\" -->\n    <!--sharding-total-count=\"${script.shardingTotalCount}\" cron=\"${script.cron}\" sharding-item-parameters=\"${script.shardingItemParameters}\" description=\"${script.description}\" -->\n    <!--overwrite=\"${script.overwrite}\">-->\n    <!--<props>-->\n    <!--<prop key=\"script.command.line\">${script.scriptCommandLine}</prop>-->\n    <!--</props>-->\n    <!--</elasticjob:job>-->\n    \n    <!-- use email error handler -->\n<!--    <bean id=\"occurErrorNoticeEmailJob\" class=\"org.apache.shardingsphere.elasticjob.kernel.example.job.simple.JavaOccurErrorJob\" />-->\n<!--    <elasticjob:job id=\"${occurErrorNoticeEmailJob.id}\" job-ref=\"occurErrorNoticeEmailJob\"-->\n<!--                    registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\"-->\n<!--                    sharding-total-count=\"${occurErrorNoticeEmailJob.shardingTotalCount}\"-->\n<!--                    cron=\"${occurErrorNoticeEmailJob.cron}\"-->\n<!--                    sharding-item-parameters=\"${occurErrorNoticeEmailJob.shardingItemParameters}\"-->\n<!--                    monitor-execution=\"${occurErrorNoticeEmailJob.monitorExecution}\"-->\n<!--                    failover=\"${occurErrorNoticeEmailJob.failover}\"-->\n<!--                    job-error-handler-type=\"${occurErrorNoticeEmailJob.jobErrorHandlerType}\"-->\n<!--                    description=\"${occurErrorNoticeEmailJob.description}\"-->\n<!--                    disabled=\"${occurErrorNoticeEmailJob.disabled}\" overwrite=\"${occurErrorNoticeEmailJob.overwrite}\">-->\n<!--        <props>-->\n<!--            <prop key=\"email.host\">host</prop>-->\n<!--            <prop key=\"email.port\">465</prop>-->\n<!--            <prop key=\"email.username\">username</prop>-->\n<!--            <prop key=\"email.password\">password</prop>-->\n<!--            <prop key=\"email.from\">from@xxx.xx</prop>-->\n<!--            <prop key=\"email.to\">to1@xxx.xx,to2@xxx.xx</prop>-->\n<!--        </props>-->\n<!--    </elasticjob:job>-->\n    \n    <!-- use dingtalk error handler -->\n<!--    <bean id=\"occurErrorNoticeDingtalkJob\" class=\"org.apache.shardingsphere.elasticjob.kernel.example.job.simple.JavaOccurErrorJob\" />-->\n<!--    <elasticjob:job id=\"${occurErrorNoticeDingtalkJob.id}\" job-ref=\"occurErrorNoticeDingtalkJob\"-->\n<!--                    registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\"-->\n<!--                    sharding-total-count=\"${occurErrorNoticeDingtalkJob.shardingTotalCount}\"-->\n<!--                    cron=\"${occurErrorNoticeDingtalkJob.cron}\"-->\n<!--                    sharding-item-parameters=\"${occurErrorNoticeDingtalkJob.shardingItemParameters}\"-->\n<!--                    monitor-execution=\"${occurErrorNoticeDingtalkJob.monitorExecution}\"-->\n<!--                    failover=\"${occurErrorNoticeDingtalkJob.failover}\"-->\n<!--                    job-error-handler-type=\"${occurErrorNoticeDingtalkJob.jobErrorHandlerType}\"-->\n<!--                    description=\"${occurErrorNoticeDingtalkJob.description}\"-->\n<!--                    disabled=\"${occurErrorNoticeDingtalkJob.disabled}\"-->\n<!--                    overwrite=\"${occurErrorNoticeDingtalkJob.overwrite}\">-->\n<!--        <props>-->\n<!--            <prop key=\"dingtalk.webhook\">https://oapi.dingtalk.com/robot/send?access_token=token</prop>-->\n<!--            <prop key=\"dingtalk.keyword\">keyword</prop>-->\n<!--            <prop key=\"dingtalk.secret\">secret</prop>-->\n<!--            <prop key=\"dingtalk.connectTimeoutMilliseconds\">3000</prop>-->\n<!--            <prop key=\"dingtalk.readTimeoutMilliseconds\">5000</prop>-->\n<!--        </props>-->\n<!--    </elasticjob:job>-->\n    \n    <!-- use wechat error handler -->\n<!--    <bean id=\"occurErrorNoticeWechatJob\" class=\"org.apache.shardingsphere.elasticjob.kernel.example.job.simple.JavaOccurErrorJob\" />-->\n<!--    <elasticjob:job id=\"${occurErrorNoticeWechatJob.id}\" job-ref=\"occurErrorNoticeWechatJob\"-->\n<!--                    registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\"-->\n<!--                    sharding-total-count=\"${occurErrorNoticeWechatJob.shardingTotalCount}\"-->\n<!--                    cron=\"${occurErrorNoticeWechatJob.cron}\"-->\n<!--                    sharding-item-parameters=\"${occurErrorNoticeWechatJob.shardingItemParameters}\"-->\n<!--                    monitor-execution=\"${occurErrorNoticeWechatJob.monitorExecution}\"-->\n<!--                    failover=\"${occurErrorNoticeWechatJob.failover}\"-->\n<!--                    job-error-handler-type=\"${occurErrorNoticeWechatJob.jobErrorHandlerType}\"-->\n<!--                    description=\"${occurErrorNoticeWechatJob.description}\"-->\n<!--                    disabled=\"${occurErrorNoticeWechatJob.disabled}\" overwrite=\"${occurErrorNoticeWechatJob.overwrite}\">-->\n<!--        <props>-->\n<!--            <prop key=\"wechat.webhook\">https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=key</prop>-->\n<!--            <prop key=\"wechat.connectTimeoutMilliseconds\">3000</prop>-->\n<!--            <prop key=\"wechat.readTimeoutMilliseconds\">5000</prop>-->\n<!--        </props>-->\n<!--    </elasticjob:job>-->\n</beans>\n"
  },
  {
    "path": "examples/elasticjob-example-spring/src/main/resources/conf/job.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nevent.rdb.driver=org.h2.Driver\nevent.rdb.url=jdbc:h2:mem:job_event_storage\nevent.rdb.username=sa\nevent.rdb.password=\n\nsimple.id=springSimpleJob\nsimple.cron=0/5 * * * * ?\nsimple.shardingTotalCount=3\nsimple.shardingItemParameters=0=Beijing,1=Shanghai,2=Guangzhou\nsimple.monitorExecution=false\nsimple.failover=true\nsimple.description=\\u53EA\\u8FD0\\u884C\\u4E00\\u6B21\\u7684\\u4F5C\\u4E1A\\u793A\\u4F8B\nsimple.disabled=false\nsimple.overwrite=true\n\ndataflow.id=springDataflowJob\ndataflow.cron=0/5 * * * * ?\ndataflow.shardingTotalCount=3\ndataflow.shardingItemParameters=0=Beijing,1=Shanghai,2=Guangzhou\ndataflow.maxTimeDiffSeconds=-1\ndataflow.monitorExecution=true\ndataflow.failover=true\ndataflow.streamingProcess=true\ndataflow.description=\\u6309\\u987A\\u5E8F\\u4E0D\\u505C\\u6B62\\u8FD0\\u884C\\u7684\\u4F5C\\u4E1A\\u793A\\u4F8B\ndataflow.disabled=false\ndataflow.overwrite=true\n\nscript.id=springScriptJob\n\n# need absolute path\nscript.scriptCommandLine=your_path/elasticjob/elasticjob-example/elasticjob-example-spring/src/main/resources/script/demo.sh\n\nscript.cron=0/5 * * * * ?\nscript.shardingTotalCount=3\nscript.shardingItemParameters=0=Beijing,1=Shanghai,2=Guangzhou\nscript.description=Script Job\nscript.overwrite=true\n\noccurErrorNoticeDingtalkJob.id=occurErrorNoticeDingtalkJob\noccurErrorNoticeDingtalkJob.cron=0/5 * * * * ?\noccurErrorNoticeDingtalkJob.shardingTotalCount=3\noccurErrorNoticeDingtalkJob.shardingItemParameters=0=Beijing,1=Shanghai,2=Guangzhou\noccurErrorNoticeDingtalkJob.monitorExecution=false\noccurErrorNoticeDingtalkJob.failover=true\noccurErrorNoticeDingtalkJob.disabled=false\noccurErrorNoticeDingtalkJob.overwrite=true\noccurErrorNoticeDingtalkJob.description=\\u53d1\\u751f\\u5f02\\u5e38\\u901a\\u77e5\\u9489\\u9489\\u793a\\u4f8b\noccurErrorNoticeDingtalkJob.jobErrorHandlerType=DINGTALK\n\noccurErrorNoticeWechatJob.id=occurErrorNoticeWechatJob\noccurErrorNoticeWechatJob.cron=0/5 * * * * ?\noccurErrorNoticeWechatJob.shardingTotalCount=3\noccurErrorNoticeWechatJob.shardingItemParameters=0=Beijing,1=Shanghai,2=Guangzhou\noccurErrorNoticeWechatJob.monitorExecution=false\noccurErrorNoticeWechatJob.failover=true\noccurErrorNoticeWechatJob.disabled=false\noccurErrorNoticeWechatJob.overwrite=true\noccurErrorNoticeWechatJob.description=\\u53d1\\u751f\\u5f02\\u5e38\\u901a\\u77e5\\u4f01\\u4e1a\\u5fae\\u4fe1\\u793a\\u4f8b\noccurErrorNoticeWechatJob.jobErrorHandlerType=WECHAT\n\noccurErrorNoticeEmailJob.id=occurErrorNoticeEmailJob\noccurErrorNoticeEmailJob.cron=0/5 * * * * ?\noccurErrorNoticeEmailJob.shardingTotalCount=3\noccurErrorNoticeEmailJob.shardingItemParameters=0=Beijing,1=Shanghai,2=Guangzhou\noccurErrorNoticeEmailJob.monitorExecution=false\noccurErrorNoticeEmailJob.failover=true\noccurErrorNoticeEmailJob.disabled=false\noccurErrorNoticeEmailJob.overwrite=true\noccurErrorNoticeEmailJob.description=\\u53d1\\u751f\\u5f02\\u5e38\\u901a\\u77e5\\u7535\\u5b50\\u90ae\\u7bb1\\u793a\\u4f8b\noccurErrorNoticeEmailJob.jobErrorHandlerType=EMAIL\n"
  },
  {
    "path": "examples/elasticjob-example-spring/src/main/resources/conf/reg.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nserverLists=localhost:5181\nnamespace=elasticjob-example-spring\nbaseSleepTimeMilliseconds=1000\nmaxSleepTimeMilliseconds=3000\nmaxRetries=3\n"
  },
  {
    "path": "examples/elasticjob-example-spring/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    \n    <property name=\"log.context.name\" value=\"elasticjob-example\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <level value=\"INFO\" />\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.zookeeper\" level=\"WARN\" />\n    <logger name=\"org.apache.curator\" level=\"WARN\" />\n</configuration>\n"
  },
  {
    "path": "examples/elasticjob-example-spring/src/main/resources/script/demo.bat",
    "content": "@rem\n@rem Licensed to the Apache Software Foundation (ASF) under one or more\n@rem contributor license agreements.  See the NOTICE file distributed with\n@rem this work for additional information regarding copyright ownership.\n@rem The ASF licenses this file to You under the Apache License, Version 2.0\n@rem (the \"License\"); you may not use this file except in compliance with\n@rem the License.  You may obtain a copy of the License at\n@rem\n@rem     http://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n\n@echo Sharding Context: %*\n"
  },
  {
    "path": "examples/elasticjob-example-spring/src/main/resources/script/demo.sh",
    "content": "#!/bin/bash\n#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\necho Sharding Context: $*\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-example</artifactId>\n        <version>${revision}</version>\n    </parent>\n    <artifactId>elasticjob-example-springboot</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <properties>\n        <springboot.version>2.5.12</springboot.version>\n        <spring.version>5.2.22.RELEASE</spring.version>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-context</artifactId>\n                <version>${spring.version}</version>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-spring-boot-starter</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-wechat</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-email</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-example-embed-zk</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-actuator</artifactId>\n            <version>${springboot.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <version>${springboot.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <version>${springboot.version}</version>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n            <version>${springboot.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n            <version>${h2.version}</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/java/org/apache/shardingsphere/elasticjob/example/SpringBootMain.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class SpringBootMain {\n    \n    // CHECKSTYLE:OFF\n    public static void main(final String[] args) {\n    // CHECKSTYLE:ON\n        EmbedZookeeperServer.start(6181);\n        SpringApplication.run(SpringBootMain.class, args);\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/java/org/apache/shardingsphere/elasticjob/example/controller/OneOffJobController.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.controller;\n\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.annotation.Resource;\n\n@RestController\npublic class OneOffJobController {\n    \n    private static final String RES_TEXT = \"{\\\"msg\\\":\\\"OK\\\"}\";\n    \n    @Resource(name = \"manualScriptJobBean\")\n    private OneOffJobBootstrap manualScriptJob;\n\n    @Autowired\n    @Qualifier(value = \"occurErrorNoticeDingtalkBean\")\n    private OneOffJobBootstrap occurErrorNoticeDingtalkJob;\n\n    @Autowired\n    @Qualifier(value = \"occurErrorNoticeWechatBean\")\n    private OneOffJobBootstrap occurErrorNoticeWechatJob;\n\n    @Autowired\n    @Qualifier(value = \"occurErrorNoticeEmailBean\")\n    private OneOffJobBootstrap occurErrorNoticeEmailJob;\n    \n    @GetMapping(\"/execute/manualScriptJob\")\n    public String executeManualScriptJob() {\n        manualScriptJob.execute();\n        return RES_TEXT;\n    }\n    \n    @GetMapping(\"/execute/occurErrorNoticeDingtalkJob\")\n    public String executeOneOffJob() {\n        occurErrorNoticeDingtalkJob.execute();\n        return RES_TEXT;\n    }\n    \n    @GetMapping(\"/execute/occurErrorNoticeWechatJob\")\n    public String executeOccurErrorNoticeWechatJob() {\n        occurErrorNoticeWechatJob.execute();\n        return RES_TEXT;\n    }\n    \n    @GetMapping(\"/execute/occurErrorNoticeEmailJob\")\n    public String executeOccurErrorNoticeEmailJob() {\n        occurErrorNoticeEmailJob.execute();\n        return RES_TEXT;\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/java/org/apache/shardingsphere/elasticjob/example/entity/Foo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.entity;\n\nimport java.io.Serializable;\n\npublic final class Foo implements Serializable {\n    \n    private static final long serialVersionUID = 2706842871078949451L;\n    \n    private final long id;\n    \n    private final String location;\n    \n    private Status status;\n    \n    public Foo(final long id, final String location, final Status status) {\n        this.id = id;\n        this.location = location;\n        this.status = status;\n    }\n    \n    public long getId() {\n        return id;\n    }\n    \n    public String getLocation() {\n        return location;\n    }\n    \n    public Status getStatus() {\n        return status;\n    }\n    \n    public void setStatus(final Status status) {\n        this.status = status;\n    }\n    \n    @Override\n    public String toString() {\n        return String.format(\"id: %s, location: %s, status: %s\", id, location, status);\n    }\n    \n    public enum Status {\n        TODO,\n        COMPLETED\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/java/org/apache/shardingsphere/elasticjob/example/job/SpringBootDataflowJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.job;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob;\nimport org.apache.shardingsphere.elasticjob.example.entity.Foo;\nimport org.apache.shardingsphere.elasticjob.example.repository.FooRepository;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.Resource;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\n@Component\npublic class SpringBootDataflowJob implements DataflowJob<Foo> {\n    \n    private final Logger logger = LoggerFactory.getLogger(SpringBootDataflowJob.class);\n    \n    @Resource\n    private FooRepository fooRepository;\n    \n    @Override\n    public List<Foo> fetchData(final ShardingContext shardingContext) {\n        logger.info(\"Item: {} | Time: {} | Thread: {} | {}\",\n                shardingContext.getShardingItem(), new SimpleDateFormat(\"HH:mm:ss\").format(new Date()), Thread.currentThread().getId(), \"DATAFLOW FETCH\");\n        return fooRepository.findTodoData(shardingContext.getShardingParameter(), 10);\n    }\n    \n    @Override\n    public void processData(final ShardingContext shardingContext, final List<Foo> data) {\n        logger.info(\"Item: {} | Time: {} | Thread: {} | {}\",\n                shardingContext.getShardingItem(), new SimpleDateFormat(\"HH:mm:ss\").format(new Date()), Thread.currentThread().getId(), \"DATAFLOW PROCESS\");\n        for (Foo each : data) {\n            fooRepository.setCompleted(each.getId());\n        }\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/java/org/apache/shardingsphere/elasticjob/example/job/SpringBootOccurErrorNoticeDingtalkJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.job;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class SpringBootOccurErrorNoticeDingtalkJob implements SimpleJob {\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        throw new RuntimeException(String.format(\"An exception has occurred in Job, The parameter is %s\", shardingContext.getShardingParameter()));\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/java/org/apache/shardingsphere/elasticjob/example/job/SpringBootOccurErrorNoticeEmailJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.job;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class SpringBootOccurErrorNoticeEmailJob implements SimpleJob {\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        throw new RuntimeException(String.format(\"An exception has occurred in Job, The parameter is %s\", shardingContext.getShardingParameter()));\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/java/org/apache/shardingsphere/elasticjob/example/job/SpringBootOccurErrorNoticeWechatJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.job;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class SpringBootOccurErrorNoticeWechatJob implements SimpleJob {\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        throw new RuntimeException(String.format(\"An exception has occurred in Job, The parameter is %s\", shardingContext.getShardingParameter()));\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/java/org/apache/shardingsphere/elasticjob/example/job/SpringBootSimpleJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.job;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.example.entity.Foo;\nimport org.apache.shardingsphere.elasticjob.example.repository.FooRepository;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\n@Component\npublic class SpringBootSimpleJob implements SimpleJob {\n    \n    private final Logger logger = LoggerFactory.getLogger(SpringBootSimpleJob.class);\n    \n    @Autowired\n    private FooRepository fooRepository;\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        logger.info(\"Item: {} | Time: {} | Thread: {} | {}\",\n                shardingContext.getShardingItem(), new SimpleDateFormat(\"HH:mm:ss\").format(new Date()), Thread.currentThread().getId(), \"SIMPLE\");\n        List<Foo> data = fooRepository.findTodoData(shardingContext.getShardingParameter(), 10);\n        for (Foo each : data) {\n            fooRepository.setCompleted(each.getId());\n        }\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/java/org/apache/shardingsphere/elasticjob/example/repository/FooRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.example.repository;\n\nimport org.apache.shardingsphere.elasticjob.example.entity.Foo;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n@Repository\npublic class FooRepository {\n    \n    private final Map<Long, Foo> data = new ConcurrentHashMap<>(300, 1);\n    \n    public FooRepository() {\n        init();\n    }\n    \n    private void init() {\n        addData(0L, 100L, \"Beijing\");\n        addData(100L, 200L, \"Shanghai\");\n        addData(200L, 300L, \"Guangzhou\");\n    }\n    \n    private void addData(final long idFrom, final long idTo, final String location) {\n        for (long i = idFrom; i < idTo; i++) {\n            data.put(i, new Foo(i, location, Foo.Status.TODO));\n        }\n    }\n    \n    public List<Foo> findTodoData(final String location, final int limit) {\n        List<Foo> result = new ArrayList<>(limit);\n        int count = 0;\n        for (Map.Entry<Long, Foo> each : data.entrySet()) {\n            Foo foo = each.getValue();\n            if (foo.getLocation().equals(location) && foo.getStatus() == Foo.Status.TODO) {\n                result.add(foo);\n                count++;\n                if (count == limit) {\n                    break;\n                }\n            }\n        }\n        return result;\n    }\n    \n    public void setCompleted(final long id) {\n        data.get(id).setStatus(Foo.Status.COMPLETED);\n    }\n}\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/resources/application-dev.yml",
    "content": "spring:\n  datasource:\n    url: jdbc:h2:mem:job_event_storage\n    driver-class-name: org.h2.Driver\n    username: sa\n    password:\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/resources/application-prod.yml",
    "content": "spring:\n  datasource:\n    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&verifyServerCertificate=false&useSSL=false&requireSSL=false\n    driver-class-name: com.mysql.jdbc.Driver\n    username: test\n    password: test\n    tomcat:\n      max-wait: 10000\n      min-idle: 0\n      initial-size: 25\n      validation-query: SELECT 1\n      test-on-borrow: false\n      test-while-idle: true\n      time-between-eviction-runs-millis: 18800\n      remove-abandoned: true\n      remove-abandoned-timeout: 180\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/resources/application.yml",
    "content": "spring:\n  profiles:\n    active: dev\n\nelasticjob:\n  tracing:\n    type: RDB\n  regCenter:\n    serverLists: localhost:6181\n    namespace: elasticjob-springboot\n  jobs:\n    simpleJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.kernel.example.job.SpringBootSimpleJob\n      cron: 0/5 * * * * ?\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n    dataflowJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.kernel.example.job.SpringBootDataflowJob\n      cron: 0/5 * * * * ?\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n    scriptJob:\n      elasticJobType: SCRIPT\n      cron: 0/10 * * * * ?\n      shardingTotalCount: 3\n      props:\n        script.command.line: \"echo SCRIPT Job: \"\n    manualScriptJob:\n      elasticJobType: SCRIPT\n      jobBootstrapBeanName: manualScriptJobBean\n      shardingTotalCount: 9\n      props:\n        script.command.line: \"echo Manual SCRIPT Job: \"\n    occurErrorNoticeDingtalkJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.kernel.example.job.SpringBootOccurErrorNoticeDingtalkJob\n      overwrite: true\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n      jobErrorHandlerType: DINGTALK\n      jobBootstrapBeanName: occurErrorNoticeDingtalkBean\n      props:\n        dingtalk:\n          webhook: you_webhook\n          keyword: you_keyword\n          secret: you_secret\n          connectTimeout: 3000\n          readTimeout: 5000\n    occurErrorNoticeWechatJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.kernel.kernel.job.SpringBootOccurErrorNoticeWechatJob\n      overwrite: true\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n      jobErrorHandlerType: WECHAT\n      jobBootstrapBeanName: occurErrorNoticeWechatBean\n      props:\n        wechat:\n          webhook: you_webhook\n          connectTimeout: 3000\n          readTimeout: 5000\n    occurErrorNoticeEmailJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.kernel.kernel.job.SpringBootOccurErrorNoticeEmailJob\n      overwrite: true\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n      jobErrorHandlerType: EMAIL\n      jobBootstrapBeanName: occurErrorNoticeEmailBean\n      props:\n        email:\n          host: host\n          port: 465\n          username: username\n          password: password\n          useSsl: true\n          subject: ElasticJob error message\n          from: from@xxx.xx\n          to: to1@xxx.xx,to2@xxx.xx\n          cc: cc@xxx.xx\n          bcc: bcc@xxx.xx\n          debug: false\n  dump:\n    port: 9888\n"
  },
  {
    "path": "examples/elasticjob-example-springboot/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    \n    <property name=\"log.context.name\" value=\"elasticjob-example\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <level value=\"INFO\" />\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.zookeeper\" level=\"WARN\" />\n    <logger name=\"org.apache.curator\" level=\"WARN\" />\n</configuration>\n"
  },
  {
    "path": "examples/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-example</artifactId>\n    <name>${project.artifactId}</name>\n    <packaging>pom</packaging>\n    <version>${revision}</version>\n    \n    <modules>\n        <module>elasticjob-example-jobs</module>\n        <module>elasticjob-example-embed-zk</module>\n        \n        <module>elasticjob-example-java</module>\n        <module>elasticjob-example-spring</module>\n        <module>elasticjob-example-springboot</module>\n    </modules>\n    \n    <properties>\n        <revision>3.0.6-SNAPSHOT</revision>\n        <java.version>1.8</java.version>\n        \n        <curator.version>5.9.0</curator.version>\n        <springframework.version>5.2.22.RELEASE</springframework.version>\n        \n        <slf4j.version>1.7.36</slf4j.version>\n        <logback.version>1.2.13</logback.version>\n        \n        <h2.version>2.2.224</h2.version>\n        <mysql-connector-java.version>8.2.0</mysql-connector-java.version>\n        \n        <hikari-cp.version>4.0.3</hikari-cp.version>\n        \n        <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>\n        <flatten-maven-plugin.version>1.2.5</flatten-maven-plugin.version>\n    </properties>\n    \n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.apache.shardingsphere.elasticjob</groupId>\n                <artifactId>elasticjob-bootstrap</artifactId>\n                <version>${revision}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.shardingsphere.elasticjob</groupId>\n                <artifactId>elasticjob-simple-executor</artifactId>\n                <version>${revision}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.shardingsphere.elasticjob</groupId>\n                <artifactId>elasticjob-spring-namespace</artifactId>\n                <version>${revision}</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.apache.curator</groupId>\n                <artifactId>curator-test</artifactId>\n                <version>${curator.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-context</artifactId>\n                <version>${springframework.version}</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>slf4j-api</artifactId>\n                <version>${slf4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>jcl-over-slf4j</artifactId>\n                <version>${slf4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>log4j-over-slf4j</artifactId>\n                <version>${slf4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>ch.qos.logback</groupId>\n                <artifactId>logback-classic</artifactId>\n                <version>${logback.version}</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>com.h2database</groupId>\n                <artifactId>h2</artifactId>\n                <version>${h2.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.mysql</groupId>\n                <artifactId>mysql-connector-j</artifactId>\n                <version>${mysql-connector-java.version}</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>com.zaxxer</groupId>\n                <artifactId>HikariCP</artifactId>\n                <version>${hikari-cp.version}</version>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    \n    <build>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <artifactId>maven-compiler-plugin</artifactId>\n                    <configuration>\n                        <source>${java.version}</source>\n                        <target>${java.version}</target>\n                        <testSource>${java.version}</testSource>\n                        <testTarget>${java.version}</testTarget>\n                    </configuration>\n                    <version>${maven-compiler-plugin.version}</version>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n        <plugins>\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>flatten-maven-plugin</artifactId>\n                <version>${flatten-maven-plugin.version}</version>\n                <configuration>\n                    <updatePomFile>true</updatePomFile>\n                    <flattenMode>resolveCiFriendliesOnly</flattenMode>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>flatten</id>\n                        <phase>process-resources</phase>\n                        <goals>\n                            <goal>flatten</goal>\n                        </goals>\n                    </execution>\n                    <execution>\n                        <id>flatten.clean</id>\n                        <phase>clean</phase>\n                        <goals>\n                            <goal>clean</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kernel/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-kernel</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-api</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-registry-center-zookeeper-curator</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-test-util</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.yaml</groupId>\n            <artifactId>snakeyaml</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.google.code.gson</groupId>\n            <artifactId>gson</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.quartz-scheduler</groupId>\n            <artifactId>quartz</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.awaitility</groupId>\n            <artifactId>awaitility</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/ElasticJobExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.error.handler.JobErrorHandlerReloader;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.facade.JobFacade;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.JobItemExecutor;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.item.JobItemExecutorFactory;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.TypedJobItemExecutor;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.ExecutorServiceReloader;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.env.IpUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.ExceptionUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionEnvironmentException;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent.ExecutionSource;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent.State;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\n\n/**\n * ElasticJob executor.\n */\n@Slf4j\npublic final class ElasticJobExecutor {\n    \n    private final ElasticJob elasticJob;\n    \n    private final JobFacade jobFacade;\n    \n    @SuppressWarnings(\"rawtypes\")\n    private final JobItemExecutor jobItemExecutor;\n    \n    private final ExecutorServiceReloader executorServiceReloader;\n    \n    private final JobErrorHandlerReloader jobErrorHandlerReloader;\n    \n    private final Map<Integer, String> itemErrorMessages;\n    \n    public ElasticJobExecutor(final ElasticJob elasticJob, final JobConfiguration jobConfig, final JobFacade jobFacade) {\n        this(elasticJob, jobConfig, jobFacade, JobItemExecutorFactory.getExecutor(elasticJob.getClass()));\n    }\n    \n    public ElasticJobExecutor(final String type, final JobConfiguration jobConfig, final JobFacade jobFacade) {\n        this(null, jobConfig, jobFacade, TypedSPILoader.getService(TypedJobItemExecutor.class, type));\n    }\n    \n    private ElasticJobExecutor(final ElasticJob elasticJob, final JobConfiguration jobConfig, final JobFacade jobFacade, final JobItemExecutor jobItemExecutor) {\n        this.elasticJob = elasticJob;\n        this.jobFacade = jobFacade;\n        this.jobItemExecutor = jobItemExecutor;\n        JobConfiguration loadedJobConfig = jobFacade.loadJobConfiguration(true);\n        executorServiceReloader = new ExecutorServiceReloader(loadedJobConfig);\n        jobErrorHandlerReloader = new JobErrorHandlerReloader(loadedJobConfig);\n        itemErrorMessages = new ConcurrentHashMap<>(jobConfig.getShardingTotalCount(), 1);\n    }\n    \n    /**\n     * Execute job.\n     */\n    public void execute() {\n        JobConfiguration jobConfig = jobFacade.loadJobConfiguration(true);\n        executorServiceReloader.reloadIfNecessary(jobConfig);\n        jobErrorHandlerReloader.reloadIfNecessary(jobConfig);\n        JobErrorHandler jobErrorHandler = jobErrorHandlerReloader.getJobErrorHandler();\n        try {\n            jobFacade.checkJobExecutionEnvironment();\n        } catch (final JobExecutionEnvironmentException cause) {\n            jobErrorHandler.handleException(jobConfig.getJobName(), cause);\n        }\n        ShardingContexts shardingContexts = jobFacade.getShardingContexts();\n        jobFacade.postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_STAGING, String.format(\"Job '%s' execute begin.\", jobConfig.getJobName()));\n        if (jobFacade.misfireIfRunning(shardingContexts.getShardingItemParameters().keySet())) {\n            jobFacade.postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_FINISHED, String.format(\n                    \"Previous job '%s' - shardingItems '%s' is still running, misfired job will start after previous job completed.\", jobConfig.getJobName(),\n                    shardingContexts.getShardingItemParameters().keySet()));\n            return;\n        }\n        try {\n            jobFacade.beforeJobExecuted(shardingContexts);\n            // CHECKSTYLE:OFF\n        } catch (final Throwable cause) {\n            // CHECKSTYLE:ON\n            jobErrorHandler.handleException(jobConfig.getJobName(), cause);\n        }\n        execute(jobConfig, shardingContexts, ExecutionSource.NORMAL_TRIGGER);\n        while (jobFacade.isExecuteMisfired(shardingContexts.getShardingItemParameters().keySet())) {\n            jobFacade.clearMisfire(shardingContexts.getShardingItemParameters().keySet());\n            execute(jobConfig, shardingContexts, ExecutionSource.MISFIRE);\n        }\n        jobFacade.failoverIfNecessary();\n        try {\n            jobFacade.afterJobExecuted(shardingContexts);\n            // CHECKSTYLE:OFF\n        } catch (final Throwable cause) {\n            // CHECKSTYLE:ON\n            jobErrorHandler.handleException(jobConfig.getJobName(), cause);\n        }\n    }\n    \n    private void execute(final JobConfiguration jobConfig, final ShardingContexts shardingContexts, final ExecutionSource executionSource) {\n        if (shardingContexts.getShardingItemParameters().isEmpty()) {\n            jobFacade.postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_FINISHED, String.format(\"Sharding item for job '%s' is empty.\", jobConfig.getJobName()));\n            return;\n        }\n        jobFacade.registerJobBegin(shardingContexts);\n        String taskId = shardingContexts.getTaskId();\n        jobFacade.postJobStatusTraceEvent(taskId, State.TASK_RUNNING, \"\");\n        try {\n            process(jobConfig, shardingContexts, executionSource);\n        } finally {\n            // TODO Consider increasing the status of job failure, and how to handle the overall loop of job failure\n            jobFacade.registerJobCompleted(shardingContexts);\n            if (itemErrorMessages.isEmpty()) {\n                jobFacade.postJobStatusTraceEvent(taskId, State.TASK_FINISHED, \"\");\n            } else {\n                jobFacade.postJobStatusTraceEvent(taskId, State.TASK_ERROR, itemErrorMessages.toString());\n                itemErrorMessages.clear();\n            }\n        }\n    }\n    \n    private void process(final JobConfiguration jobConfig, final ShardingContexts shardingContexts, final ExecutionSource executionSource) {\n        Collection<Integer> items = shardingContexts.getShardingItemParameters().keySet();\n        if (1 == items.size()) {\n            int item = shardingContexts.getShardingItemParameters().keySet().iterator().next();\n            JobExecutionEvent jobExecutionEvent = new JobExecutionEvent(IpUtils.getHostName(), IpUtils.getIp(), shardingContexts.getTaskId(), jobConfig.getJobName(), executionSource, item);\n            process(jobConfig, shardingContexts, item, jobExecutionEvent);\n            return;\n        }\n        CountDownLatch latch = new CountDownLatch(items.size());\n        for (int each : items) {\n            JobExecutionEvent jobExecutionEvent = new JobExecutionEvent(IpUtils.getHostName(), IpUtils.getIp(), shardingContexts.getTaskId(), jobConfig.getJobName(), executionSource, each);\n            ExecutorService executorService = executorServiceReloader.getExecutorService();\n            if (executorService.isShutdown()) {\n                return;\n            }\n            executorService.submit(() -> {\n                try {\n                    process(jobConfig, shardingContexts, each, jobExecutionEvent);\n                } finally {\n                    latch.countDown();\n                }\n            });\n        }\n        try {\n            latch.await();\n        } catch (final InterruptedException ex) {\n            Thread.currentThread().interrupt();\n        }\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    private void process(final JobConfiguration jobConfig, final ShardingContexts shardingContexts, final int item, final JobExecutionEvent startEvent) {\n        jobFacade.postJobExecutionEvent(startEvent);\n        log.trace(\"Job '{}' executing, item is: '{}'.\", jobConfig.getJobName(), item);\n        JobExecutionEvent completeEvent;\n        try {\n            jobItemExecutor.process(elasticJob, jobConfig, jobFacade.getJobRuntimeService(), shardingContexts.createShardingContext(item));\n            completeEvent = startEvent.executionSuccess();\n            log.trace(\"Job '{}' executed, item is: '{}'.\", jobConfig.getJobName(), item);\n            jobFacade.postJobExecutionEvent(completeEvent);\n            // CHECKSTYLE:OFF\n        } catch (final Throwable cause) {\n            // CHECKSTYLE:ON\n            completeEvent = startEvent.executionFailure(ExceptionUtils.transform(cause));\n            jobFacade.postJobExecutionEvent(completeEvent);\n            itemErrorMessages.put(item, ExceptionUtils.transform(cause));\n            JobErrorHandler jobErrorHandler = jobErrorHandlerReloader.getJobErrorHandler();\n            jobErrorHandler.handleException(jobConfig.getJobName(), cause);\n        }\n    }\n    \n    /**\n     * Shutdown executor.\n     */\n    public void shutdown() {\n        executorServiceReloader.close();\n        jobErrorHandlerReloader.close();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/error/handler/JobErrorHandlerReloader.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.error.handler;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\n\nimport java.io.Closeable;\nimport java.util.Properties;\n\n/**\n * Job error handler reloader.\n */\npublic final class JobErrorHandlerReloader implements Closeable {\n    \n    private Properties props;\n    \n    @Getter\n    private JobErrorHandler jobErrorHandler;\n    \n    public JobErrorHandlerReloader(final JobConfiguration jobConfig) {\n        init(jobConfig);\n    }\n    \n    /**\n     * Reload if necessary.\n     *\n     * @param jobConfig job configuration\n     */\n    public synchronized void reloadIfNecessary(final JobConfiguration jobConfig) {\n        if (jobErrorHandler.getType().equals(jobConfig.getJobErrorHandlerType()) && props.equals(jobConfig.getProps())) {\n            return;\n        }\n        jobErrorHandler.close();\n        init(jobConfig);\n    }\n    \n    private void init(final JobConfiguration jobConfig) {\n        props = jobConfig.getProps();\n        jobErrorHandler = TypedSPILoader.getService(JobErrorHandler.class, jobConfig.getJobErrorHandlerType(), props);\n    }\n    \n    @Override\n    public void close() {\n        jobErrorHandler.close();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/facade/AbstractJobFacade.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.facade;\n\nimport com.google.common.base.Strings;\n\nimport java.util.Collection;\nimport java.util.Comparator;\nimport java.util.stream.Collectors;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionEnvironmentException;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.context.TaskContext;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionContextService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.event.JobTracingEventBus;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent.State;\n\nimport lombok.extern.slf4j.Slf4j;\n\n/**\n * Abstract Job facade.\n */\n@Slf4j\nabstract class AbstractJobFacade implements JobFacade {\n    \n    private final ConfigurationService configService;\n    \n    private final ShardingService shardingService;\n    \n    private final ExecutionContextService executionContextService;\n    \n    private final ExecutionService executionService;\n    \n    private final FailoverService failoverService;\n    \n    private final Collection<ElasticJobListener> elasticJobListeners;\n    \n    private final JobTracingEventBus jobTracingEventBus;\n    \n    AbstractJobFacade(final CoordinatorRegistryCenter regCenter, final String jobName, final Collection<ElasticJobListener> elasticJobListeners, final TracingConfiguration<?> tracingConfig) {\n        configService = new ConfigurationService(regCenter, jobName);\n        shardingService = new ShardingService(regCenter, jobName);\n        executionContextService = new ExecutionContextService(regCenter, jobName);\n        executionService = new ExecutionService(regCenter, jobName);\n        failoverService = new FailoverService(regCenter, jobName);\n        this.elasticJobListeners = elasticJobListeners.stream().sorted(Comparator.comparingInt(ElasticJobListener::order)).collect(Collectors.toList());\n        this.jobTracingEventBus = null == tracingConfig ? new JobTracingEventBus() : new JobTracingEventBus(tracingConfig);\n    }\n    \n    /**\n     * Load job configuration.\n     *\n     * @param fromCache load from cache or not\n     * @return job configuration\n     */\n    @Override\n    public JobConfiguration loadJobConfiguration(final boolean fromCache) {\n        return configService.load(fromCache);\n    }\n    \n    /**\n     * Check job execution environment.\n     *\n     * @throws org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionEnvironmentException job execution environment exception\n     */\n    @Override\n    public void checkJobExecutionEnvironment() throws JobExecutionEnvironmentException {\n        configService.checkMaxTimeDiffSecondsTolerable();\n    }\n    \n    /**\n     * Failover If necessary.\n     */\n    @Override\n    public void failoverIfNecessary() {\n        if (configService.load(true).isFailover()) {\n            failoverService.failoverIfNecessary();\n        }\n    }\n    \n    /**\n     * Register job begin.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    @Override\n    public void registerJobBegin(final ShardingContexts shardingContexts) {\n        executionService.registerJobBegin(shardingContexts);\n    }\n    \n    /**\n     * Register job completed.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    @Override\n    public void registerJobCompleted(final ShardingContexts shardingContexts) {\n        executionService.registerJobCompleted(shardingContexts);\n        if (configService.load(true).isFailover()) {\n            failoverService.updateFailoverComplete(shardingContexts.getShardingItemParameters().keySet());\n        }\n    }\n    \n    public abstract ShardingContexts getShardingContexts();\n    \n    /**\n     * Set task misfire flag.\n     *\n     * @param shardingItems sharding items to be set misfire flag\n     * @return whether satisfy misfire condition\n     */\n    @Override\n    public boolean misfireIfRunning(final Collection<Integer> shardingItems) {\n        return executionService.misfireIfHasRunningItems(shardingItems);\n    }\n    \n    /**\n     * Clear misfire flag.\n     *\n     * @param shardingItems sharding items to be cleared misfire flag\n     */\n    @Override\n    public void clearMisfire(final Collection<Integer> shardingItems) {\n        executionService.clearMisfire(shardingItems);\n    }\n    \n    /**\n     * Judge job whether to need to execute misfire tasks.\n     *\n     * @param shardingItems sharding items\n     * @return need to execute misfire tasks or not\n     */\n    @Override\n    public boolean isExecuteMisfired(final Collection<Integer> shardingItems) {\n        return configService.load(true).isMisfire() && !isNeedSharding() && !executionService.getMisfiredJobItems(shardingItems).isEmpty();\n    }\n    \n    /**\n     * Judge job whether to need resharding.\n     *\n     * @return need resharding or not\n     */\n    @Override\n    public boolean isNeedSharding() {\n        return shardingService.isNeedSharding();\n    }\n    \n    /**\n     * Call before job executed.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    @Override\n    public void beforeJobExecuted(final ShardingContexts shardingContexts) {\n        for (ElasticJobListener each : elasticJobListeners) {\n            each.beforeJobExecuted(shardingContexts);\n        }\n    }\n    \n    /**\n     * Call after job executed.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    @Override\n    public void afterJobExecuted(final ShardingContexts shardingContexts) {\n        for (ElasticJobListener each : elasticJobListeners) {\n            each.afterJobExecuted(shardingContexts);\n        }\n    }\n    \n    /**\n     * Post job execution event.\n     *\n     * @param jobExecutionEvent job execution event\n     */\n    @Override\n    public void postJobExecutionEvent(final JobExecutionEvent jobExecutionEvent) {\n        jobTracingEventBus.post(jobExecutionEvent);\n    }\n    \n    /**\n     * Post job status trace event.\n     *\n     * @param taskId task Id\n     * @param state job state\n     * @param message job message\n     */\n    @Override\n    public void postJobStatusTraceEvent(final String taskId, final State state, final String message) {\n        TaskContext taskContext = TaskContext.from(taskId);\n        jobTracingEventBus.post(new JobStatusTraceEvent(taskContext.getMetaInfo().getJobName(), taskContext.getId(),\n                taskContext.getSlaveId(), taskContext.getType(), taskContext.getMetaInfo().getShardingItems().toString(), state, message));\n        if (!Strings.isNullOrEmpty(message)) {\n            log.trace(message);\n        }\n    }\n    \n    /**\n     * Get job runtime service.\n     *\n     * @return job runtime service\n     */\n    @Override\n    public JobRuntimeService getJobRuntimeService() {\n        return new JobJobRuntimeServiceImpl(this);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/facade/JobFacade.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.facade;\n\nimport java.util.Collection;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionEnvironmentException;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent;\n\n/**\n * Job facade.\n */\npublic interface JobFacade {\n    \n    /**\n     * Load job configuration.\n     * \n     * @param fromCache load from cache or not\n     * @return job configuration\n     */\n    JobConfiguration loadJobConfiguration(boolean fromCache);\n    \n    /**\n     * Check job execution environment.\n     * \n     * @throws JobExecutionEnvironmentException job execution environment exception\n     */\n    void checkJobExecutionEnvironment() throws JobExecutionEnvironmentException;\n    \n    /**\n     * Failover If necessary.\n     */\n    void failoverIfNecessary();\n    \n    /**\n     * Register job begin.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    void registerJobBegin(ShardingContexts shardingContexts);\n    \n    /**\n     * Register job completed.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    void registerJobCompleted(ShardingContexts shardingContexts);\n    \n    /**\n     * Get sharding contexts.\n     *\n     * @return sharding contexts\n     */\n    ShardingContexts getShardingContexts();\n    \n    /**\n     * Set task misfire flag.\n     *\n     * @param shardingItems sharding items to be set misfire flag\n     * @return whether satisfy misfire condition\n     */\n    boolean misfireIfRunning(Collection<Integer> shardingItems);\n    \n    /**\n     * Clear misfire flag.\n     *\n     * @param shardingItems sharding items to be cleared misfire flag\n     */\n    void clearMisfire(Collection<Integer> shardingItems);\n    \n    /**\n     * Judge job whether need to execute misfire tasks.\n     * \n     * @param shardingItems sharding items\n     * @return whether need to execute misfire tasks\n     */\n    boolean isExecuteMisfired(Collection<Integer> shardingItems);\n    \n    /**\n     * Judge job whether need resharding.\n     *\n     * @return whether need resharding\n     */\n    boolean isNeedSharding();\n    \n    /**\n     * Call before job executed.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    void beforeJobExecuted(ShardingContexts shardingContexts);\n    \n    /**\n     * Call after job executed.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    void afterJobExecuted(ShardingContexts shardingContexts);\n    \n    /**\n     * Post job execution event.\n     *\n     * @param jobExecutionEvent job execution event\n     */\n    void postJobExecutionEvent(JobExecutionEvent jobExecutionEvent);\n    \n    /**\n     * Post job status trace event.\n     *\n     * @param taskId task Id\n     * @param state job state\n     * @param message job message\n     */\n    void postJobStatusTraceEvent(String taskId, JobStatusTraceEvent.State state, String message);\n    \n    /**\n     * Get job runtime service.\n     *\n     * @return job runtime service\n     */\n    JobRuntimeService getJobRuntimeService();\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/facade/JobJobRuntimeServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.facade;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\n\n/**\n * Job runtime service implementation.\n */\n@RequiredArgsConstructor\npublic final class JobJobRuntimeServiceImpl implements JobRuntimeService {\n    \n    private final JobFacade jobFacade;\n    \n    @Override\n    public boolean isNeedSharding() {\n        return jobFacade.isNeedSharding();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/facade/ShardingJobFacade.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.facade;\n\nimport lombok.extern.slf4j.Slf4j;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionContextService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.event.JobTracingEventBus;\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\n\nimport java.util.Collection;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * Sharding Job facade.\n */\n@Slf4j\npublic final class ShardingJobFacade extends AbstractJobFacade {\n    \n    private final ConfigurationService configService;\n    \n    private final ShardingService shardingService;\n    \n    private final ExecutionContextService executionContextService;\n    \n    private final ExecutionService executionService;\n    \n    private final FailoverService failoverService;\n    \n    private final Collection<ElasticJobListener> elasticJobListeners;\n    \n    private final JobTracingEventBus jobTracingEventBus;\n    \n    public ShardingJobFacade(final CoordinatorRegistryCenter regCenter, final String jobName, final Collection<ElasticJobListener> elasticJobListeners, final TracingConfiguration<?> tracingConfig) {\n        super(regCenter, jobName, elasticJobListeners, tracingConfig);\n        \n        configService = new ConfigurationService(regCenter, jobName);\n        shardingService = new ShardingService(regCenter, jobName);\n        executionContextService = new ExecutionContextService(regCenter, jobName);\n        executionService = new ExecutionService(regCenter, jobName);\n        failoverService = new FailoverService(regCenter, jobName);\n        this.elasticJobListeners = elasticJobListeners.stream().sorted(Comparator.comparingInt(ElasticJobListener::order)).collect(Collectors.toList());\n        this.jobTracingEventBus = null == tracingConfig ? new JobTracingEventBus() : new JobTracingEventBus(tracingConfig);\n    }\n    \n    /**\n     * Get sharding contexts.\n     *\n     * @return sharding contexts\n     */\n    @Override\n    public ShardingContexts getShardingContexts() {\n        boolean isFailover = configService.load(true).isFailover();\n        if (isFailover) {\n            List<Integer> failoverShardingItems = failoverService.getLocalFailoverItems();\n            if (!failoverShardingItems.isEmpty()) {\n                return executionContextService.getJobShardingContext(failoverShardingItems);\n            }\n        }\n        shardingService.shardingIfNecessary();\n        List<Integer> shardingItems = shardingService.getLocalShardingItems();\n        if (isFailover) {\n            shardingItems.removeAll(failoverService.getLocalTakeOffItems());\n        }\n        shardingItems.removeAll(executionService.getDisabledItems(shardingItems));\n        return executionContextService.getJobShardingContext(shardingItems);\n    }\n    \n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/facade/SingleShardingJobFacade.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.facade;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionContextService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.event.JobTracingEventBus;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\n\nimport lombok.extern.slf4j.Slf4j;\n\n/**\n * Single Sharding Job facade.\n */\n@Slf4j\npublic final class SingleShardingJobFacade extends AbstractJobFacade {\n    \n    private final ConfigurationService configService;\n    \n    private final ShardingService shardingService;\n    \n    private final ExecutionContextService executionContextService;\n    \n    private final ExecutionService executionService;\n    \n    private final FailoverService failoverService;\n    \n    private final Collection<ElasticJobListener> elasticJobListeners;\n    \n    private final JobTracingEventBus jobTracingEventBus;\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    private final InstanceService instanceService;\n    \n    public SingleShardingJobFacade(final CoordinatorRegistryCenter regCenter, final String jobName, final Collection<ElasticJobListener> elasticJobListeners,\n                                   final TracingConfiguration<?> tracingConfig) {\n        super(regCenter, jobName, elasticJobListeners, tracingConfig);\n        \n        configService = new ConfigurationService(regCenter, jobName);\n        shardingService = new ShardingService(regCenter, jobName);\n        executionContextService = new ExecutionContextService(regCenter, jobName);\n        executionService = new ExecutionService(regCenter, jobName);\n        failoverService = new FailoverService(regCenter, jobName);\n        this.elasticJobListeners = elasticJobListeners.stream().sorted(Comparator.comparingInt(ElasticJobListener::order)).collect(Collectors.toList());\n        this.jobTracingEventBus = null == tracingConfig ? new JobTracingEventBus() : new JobTracingEventBus(tracingConfig);\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        instanceService = new InstanceService(regCenter, jobName);\n    }\n    \n    @Override\n    public void registerJobCompleted(final ShardingContexts shardingContexts) {\n        super.registerJobCompleted(shardingContexts);\n        \n        JobConfiguration jobConfig = configService.load(true);\n        JobInstance jobInst = JobRegistry.getInstance().getJobInstance(jobConfig.getJobName());\n        if (null == jobInst) {\n            log.warn(\"Error! Can't find the job instance with name:{}\", jobConfig.getJobName());\n            return;\n        }\n        Integer nextIndex = null;\n        List<JobInstance> availJobInst = instanceService.getAvailableJobInstances();\n        for (int i = 0; i < availJobInst.size(); i++) {\n            JobInstance temp = availJobInst.get(i);\n            if (temp.getServerIp().equals(jobInst.getServerIp())) {\n                nextIndex = i + 1;\n                break;\n            }\n        }\n        if (nextIndex != null) {\n            nextIndex = nextIndex >= availJobInst.size() ? 0 : nextIndex;\n            jobNodeStorage.fillEphemeralJobNode(\"next-job-instance-ip\", availJobInst.get(nextIndex).getServerIp());\n        }\n        \n        if (log.isDebugEnabled()) {\n            log.debug(\"job name: {}, next index: {}, sharding total count: {}\",\n                    jobConfig.getJobName(), nextIndex, jobConfig.getShardingTotalCount());\n        }\n    }\n    \n    /**\n     * Get sharding contexts.\n     *\n     * @return sharding contexts\n     */\n    @Override\n    public ShardingContexts getShardingContexts() {\n        JobConfiguration jobConfig = configService.load(true);\n        boolean isFailover = jobConfig.isFailover();\n        if (isFailover) {\n            List<Integer> failoverShardingItems = failoverService.getLocalFailoverItems();\n            if (!failoverShardingItems.isEmpty()) {\n                return executionContextService.getJobShardingContext(failoverShardingItems);\n            }\n        }\n        \n        List<Integer> shardingItems;\n        String nextJobInstIP = null;\n        if (isNeedSharding()) {\n            shardingService.shardingIfNecessary();\n            shardingItems = shardingService.getLocalShardingItems();\n        } else {\n            nextJobInstIP = jobNodeStorage.getJobNodeDataDirectly(\"next-job-instance-ip\");\n            if (StringUtils.isBlank(nextJobInstIP)) {\n                shardingService.shardingIfNecessary();\n                shardingItems = shardingService.getLocalShardingItems();\n            } else {\n                JobInstance jobInst = JobRegistry.getInstance().getJobInstance(jobConfig.getJobName());\n                shardingItems = nextJobInstIP.equals(jobInst.getServerIp()) ? Collections.singletonList(0) : new ArrayList<>();\n            }\n        }\n        if (log.isDebugEnabled()) {\n            log.debug(\"job name: {}, sharding items: {}, nextJobInstIP: {}, sharding total count: {}, isFailover: {}\",\n                    jobConfig.getJobName(), shardingItems, nextJobInstIP, jobConfig.getShardingTotalCount(), isFailover);\n        }\n        \n        if (isFailover) {\n            shardingItems.removeAll(failoverService.getLocalTakeOffItems());\n        }\n        shardingItems.removeAll(executionService.getDisabledItems(shardingItems));\n        return executionContextService.getJobShardingContext(shardingItems);\n    }\n    \n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/item/JobItemExecutorFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.item;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.JobItemExecutor;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\nimport org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;\n\n/**\n * Job item executor factory.\n */\n@SuppressWarnings(\"rawtypes\")\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class JobItemExecutorFactory {\n    \n    /**\n     * Get executor.\n     * \n     * @param elasticJobClass elastic job class\n     * @return job item executor\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static JobItemExecutor getExecutor(final Class<? extends ElasticJob> elasticJobClass) {\n        for (ClassedJobItemExecutor each : ShardingSphereServiceLoader.getServiceInstances(ClassedJobItemExecutor.class)) {\n            if (each.getElasticJobClass().isAssignableFrom(elasticJobClass)) {\n                return each;\n            }\n        }\n        throw new JobConfigurationException(\"Can not find executor for elastic job class `%s`\", elasticJobClass.getName());\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/threadpool/ElasticJobExecutorService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.threadpool;\n\nimport com.google.common.util.concurrent.MoreExecutors;\nimport org.apache.commons.lang3.concurrent.BasicThreadFactory;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * ElasticJob executor service.\n */\npublic final class ElasticJobExecutorService {\n    \n    private final ThreadPoolExecutor threadPoolExecutor;\n    \n    private final BlockingQueue<Runnable> workQueue;\n    \n    public ElasticJobExecutorService(final String namingPattern, final int threadSize) {\n        workQueue = new LinkedBlockingQueue<>();\n        threadPoolExecutor = new ThreadPoolExecutor(\n                threadSize, threadSize, 5L, TimeUnit.MINUTES, workQueue, new BasicThreadFactory.Builder().namingPattern(String.join(\"-\", namingPattern, \"%s\")).build());\n        threadPoolExecutor.allowCoreThreadTimeOut(true);\n    }\n    \n    /**\n     * Create executor service.\n     *\n     * @return executor service\n     */\n    public ExecutorService createExecutorService() {\n        return MoreExecutors.listeningDecorator(MoreExecutors.getExitingExecutorService(threadPoolExecutor));\n    }\n    \n    /**\n     * Whether the threadPoolExecutor has been shut down.\n     *\n     * @return Whether the threadPoolExecutor has been shut down\n     */\n    public boolean isShutdown() {\n        return threadPoolExecutor.isShutdown();\n    }\n    \n    /**\n     * Get active thread count.\n     *\n     * @return active thread count\n     */\n    public int getActiveThreadCount() {\n        return threadPoolExecutor.getActiveCount();\n    }\n    \n    /**\n     * Get work queue size.\n     *\n     * @return work queue size\n     */\n    public int getWorkQueueSize() {\n        return workQueue.size();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/threadpool/ExecutorServiceReloader.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.threadpool;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\n\nimport java.io.Closeable;\nimport java.util.concurrent.ExecutorService;\n\n/**\n * Executor service reloader.\n */\npublic final class ExecutorServiceReloader implements Closeable {\n    \n    private String jobExecutorThreadPoolSizeProviderType;\n    \n    @Getter\n    private ExecutorService executorService;\n    \n    public ExecutorServiceReloader(final JobConfiguration jobConfig) {\n        init(jobConfig);\n    }\n    \n    /**\n     * Reload if necessary.\n     *\n     * @param jobConfig job configuration\n     */\n    public synchronized void reloadIfNecessary(final JobConfiguration jobConfig) {\n        if (jobExecutorThreadPoolSizeProviderType.equals(jobConfig.getJobExecutorThreadPoolSizeProviderType())) {\n            return;\n        }\n        executorService.shutdownNow();\n        init(jobConfig);\n    }\n    \n    private void init(final JobConfiguration jobConfig) {\n        JobExecutorThreadPoolSizeProvider jobExecutorThreadPoolSizeProvider = TypedSPILoader.getService(JobExecutorThreadPoolSizeProvider.class, jobConfig.getJobExecutorThreadPoolSizeProviderType());\n        jobExecutorThreadPoolSizeProviderType = jobExecutorThreadPoolSizeProvider.getType();\n        executorService = new ElasticJobExecutorService(\"elasticjob-\" + jobConfig.getJobName(), jobExecutorThreadPoolSizeProvider.getSize()).createExecutorService();\n    }\n    \n    @Override\n    public void close() {\n        executorService.shutdownNow();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/threadpool/JobExecutorThreadPoolSizeProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.threadpool;\n\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;\n\n/**\n * Job executor thread pool size provider.\n */\n@SingletonSPI\npublic interface JobExecutorThreadPoolSizeProvider extends TypedSPI {\n    \n    /**\n     * Get thread pool size.\n     * \n     * @return thread pool size\n     */\n    int getSize();\n    \n    @Override\n    String getType();\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/threadpool/type/CPUUsageJobExecutorThreadPoolSizeProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.threadpool.type;\n\nimport org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.JobExecutorThreadPoolSizeProvider;\n\n/**\n * Job executor pool size provider with use CPU available processors.\n */\npublic final class CPUUsageJobExecutorThreadPoolSizeProvider implements JobExecutorThreadPoolSizeProvider {\n    \n    @Override\n    public int getSize() {\n        return Runtime.getRuntime().availableProcessors() * 2;\n    }\n    \n    @Override\n    public String getType() {\n        return \"CPU\";\n    }\n    \n    @Override\n    public boolean isDefault() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/executor/threadpool/type/SingleThreadJobExecutorThreadPoolSizeProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.threadpool.type;\n\nimport org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.JobExecutorThreadPoolSizeProvider;\n\n/**\n * Job executor pool size provider with single thread.\n */\npublic final class SingleThreadJobExecutorThreadPoolSizeProvider implements JobExecutorThreadPoolSizeProvider {\n    \n    @Override\n    public int getSize() {\n        return 1;\n    }\n    \n    @Override\n    public String getType() {\n        return \"SINGLE_THREAD\";\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/env/HostException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.env;\n\nimport java.io.IOException;\n\n/**\n * Host exception.\n */\npublic final class HostException extends RuntimeException {\n    \n    private static final long serialVersionUID = 3589264847881174997L;\n    \n    public HostException(final IOException cause) {\n        super(cause);\n    }\n    \n    public HostException(final String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/env/IpUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.env;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\nimport java.io.IOException;\nimport java.net.Inet6Address;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.net.UnknownHostException;\nimport java.util.Enumeration;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Objects;\n\n/**\n * IP address utility.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class IpUtils {\n    \n    public static final String IP_REGEX = \"((\\\\d|[1-9]\\\\d|1\\\\d{2}|2[0-4]\\\\d|25[0-5])(\\\\.(1\\\\d{2}|2[0-4]\\\\d|25[0-5]|[1-9]\\\\d|\\\\d)){3})\";\n    \n    public static final String PREFERRED_NETWORK_INTERFACE = \"elasticjob.preferred.network.interface\";\n    \n    public static final String PREFERRED_NETWORK_IP = \"elasticjob.preferred.network.ip\";\n    \n    private static volatile String cachedIpAddress;\n    \n    private static volatile String cachedHostName;\n    \n    /**\n     * Get IP address for localhost.\n     * \n     * @return IP address for localhost\n     */\n    public static String getIp() {\n        if (null != cachedIpAddress) {\n            return cachedIpAddress;\n        }\n        NetworkInterface networkInterface = findNetworkInterface();\n        if (null != networkInterface) {\n            Enumeration<InetAddress> ipAddresses = networkInterface.getInetAddresses();\n            while (ipAddresses.hasMoreElements()) {\n                InetAddress ipAddress = ipAddresses.nextElement();\n                if (isValidAddress(ipAddress) && isPreferredAddress(ipAddress)) {\n                    cachedIpAddress = ipAddress.getHostAddress();\n                    return cachedIpAddress;\n                }\n            }\n        }\n        throw new HostException(\"ip is null\");\n    }\n    \n    private static NetworkInterface findNetworkInterface() {\n        Enumeration<NetworkInterface> interfaces;\n        try {\n            interfaces = NetworkInterface.getNetworkInterfaces();\n        } catch (final SocketException ex) {\n            throw new HostException(ex);\n        }\n        List<NetworkInterface> validNetworkInterfaces = new LinkedList<>();\n        while (interfaces.hasMoreElements()) {\n            NetworkInterface networkInterface = interfaces.nextElement();\n            if (ignoreNetworkInterface(networkInterface)) {\n                continue;\n            }\n            validNetworkInterfaces.add(networkInterface);\n        }\n        NetworkInterface result = null;\n        for (NetworkInterface each : validNetworkInterfaces) {\n            if (isPreferredNetworkInterface(each)) {\n                result = each;\n                break;\n            }\n        }\n        if (null == result) {\n            result = getFirstNetworkInterface(validNetworkInterfaces);\n        }\n        return result;\n    }\n    \n    private static NetworkInterface getFirstNetworkInterface(final List<NetworkInterface> validNetworkInterfaces) {\n        NetworkInterface result = null;\n        for (NetworkInterface each : validNetworkInterfaces) {\n            Enumeration<InetAddress> addresses = each.getInetAddresses();\n            while (addresses.hasMoreElements()) {\n                InetAddress inetAddress = addresses.nextElement();\n                if (isValidAddress(inetAddress) && isPreferredAddress(inetAddress)) {\n                    result = each;\n                    break;\n                }\n            }\n        }\n        if (null == result && !validNetworkInterfaces.isEmpty()) {\n            result = validNetworkInterfaces.get(0);\n        }\n        return result;\n    }\n    \n    private static boolean isPreferredNetworkInterface(final NetworkInterface networkInterface) {\n        String preferredNetworkInterface = System.getProperty(PREFERRED_NETWORK_INTERFACE);\n        return Objects.equals(networkInterface.getDisplayName(), preferredNetworkInterface);\n    }\n    \n    private static boolean ignoreNetworkInterface(final NetworkInterface networkInterface) {\n        try {\n            return null == networkInterface\n                    || networkInterface.isLoopback()\n                    || networkInterface.isVirtual()\n                    || !networkInterface.isUp();\n        } catch (final SocketException ex) {\n            return true;\n        }\n    }\n    \n    private static boolean isPreferredAddress(final InetAddress inetAddress) {\n        String preferredNetworkIp = System.getProperty(PREFERRED_NETWORK_IP);\n        if (null == preferredNetworkIp) {\n            return true;\n        }\n        String hostAddress = inetAddress.getHostAddress();\n        return hostAddress.startsWith(preferredNetworkIp) || hostAddress.matches(preferredNetworkIp);\n    }\n    \n    private static boolean isValidAddress(final InetAddress inetAddress) {\n        try {\n            return !inetAddress.isLoopbackAddress() && !inetAddress.isAnyLocalAddress()\n                    && !isIp6Address(inetAddress) && inetAddress.isReachable(100);\n        } catch (final IOException ex) {\n            return false;\n        }\n    }\n    \n    private static boolean isIp6Address(final InetAddress ipAddress) {\n        return ipAddress instanceof Inet6Address;\n    }\n    \n    /**\n     * Get host name for localhost.\n     * \n     * @return host name for localhost\n     */\n    public static String getHostName() {\n        if (null != cachedHostName) {\n            return cachedHostName;\n        }\n        try {\n            cachedHostName = InetAddress.getLocalHost().getHostName();\n        } catch (final UnknownHostException ex) {\n            cachedHostName = \"unknown\";\n        }\n        return cachedHostName;\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/ExceptionUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\n/**\n * Exception utilities.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class ExceptionUtils {\n    \n    /**\n     * Transform throwable to string.\n     *\n     * @param cause cause\n     * @return string\n     */\n    public static String transform(final Throwable cause) {\n        if (null == cause) {\n            return \"\";\n        }\n        StringWriter result = new StringWriter();\n        try (PrintWriter writer = new PrintWriter(result)) {\n            cause.printStackTrace(writer);\n        }\n        return result.toString();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/JobConfigurationException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\n/**\n * Job configuration exception.\n */\npublic final class JobConfigurationException extends RuntimeException {\n    \n    private static final long serialVersionUID = 3244988974343209468L;\n    \n    public JobConfigurationException(final String errorMessage, final Object... args) {\n        super(String.format(errorMessage, args));\n    }\n    \n    public JobConfigurationException(final Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/JobExecutionEnvironmentException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\n/**\n * Job execution environment exception.\n */\npublic final class JobExecutionEnvironmentException extends Exception {\n    \n    private static final long serialVersionUID = -6670738108926897433L;\n    \n    public JobExecutionEnvironmentException(final String errorMessage, final Object... args) {\n        super(String.format(errorMessage, args));\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/JobExecutionException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\n/**\n * Job execution exception.\n */\npublic final class JobExecutionException extends RuntimeException {\n    \n    private static final long serialVersionUID = -1701186463023700392L;\n    \n    public JobExecutionException(final Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/JobSystemException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\n/**\n * Job system exception.\n */\npublic final class JobSystemException extends RuntimeException {\n    \n    private static final long serialVersionUID = 5018901344199973515L;\n    \n    public JobSystemException(final String errorMessage, final Object... args) {\n        super(String.format(errorMessage, args));\n    }\n    \n    public JobSystemException(final String errorMessage, final Throwable cause) {\n        super(errorMessage, cause);\n    }\n    \n    public JobSystemException(final Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/PropertiesPreconditions.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\nimport com.google.common.base.Preconditions;\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\nimport java.util.Properties;\n\n/**\n * Properties preconditions.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class PropertiesPreconditions {\n    \n    /**\n     * Check property value is required.\n     * \n     * @param props properties to be checked\n     * @param key property key to be checked\n     */\n    public static void checkRequired(final Properties props, final String key) {\n        Preconditions.checkArgument(props.containsKey(key), \"The property `%s` is required.\", key);\n    }\n    \n    /**\n     * Check property value is positive integer.\n     * \n     * @param props properties to be checked\n     * @param key property key to be checked\n     */\n    public static void checkPositiveInteger(final Properties props, final String key) {\n        String propertyValue = props.getProperty(key);\n        if (null == propertyValue) {\n            return;\n        }\n        int integerValue;\n        try {\n            integerValue = Integer.parseInt(propertyValue);\n        } catch (final NumberFormatException ignored) {\n            throw new IllegalArgumentException(String.format(\"The property `%s` should be integer.\", key));\n        }\n        Preconditions.checkArgument(integerValue > 0, \"The property `%s` should be positive.\", key);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/json/GsonFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.json;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n/**\n * Gson factory.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class GsonFactory {\n    \n    private static final Gson GSON = new GsonBuilder().create();\n    \n    /**\n     * Get gson instance.\n     *\n     * @return gson instance\n     */\n    public static Gson getGson() {\n        return GSON;\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/time/TimeService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.time;\n\n/**\n * Time service.\n */\npublic final class TimeService {\n    \n    /**\n     * Get current millis.\n     * \n     * @return current millis\n     */\n    public long getCurrentMillis() {\n        return System.currentTimeMillis();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/util/BlockUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.util;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n/**\n * Block utility.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class BlockUtils {\n    \n    private static final long SLEEP_INTERVAL_MILLIS = 100L;\n    \n    /**\n     * Waiting short time.\n     */\n    public static void waitingShortTime() {\n        try {\n            Thread.sleep(SLEEP_INTERVAL_MILLIS);\n        } catch (final InterruptedException ex) {\n            Thread.currentThread().interrupt();\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/util/SensitiveInfoUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.util;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.env.IpUtils;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\n/**\n * Sensitive info utility.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class SensitiveInfoUtils {\n    \n    private static final String FAKE_IP_SAMPLE = \"ip\";\n    \n    private static final Pattern IP_PATTERN = Pattern.compile(IpUtils.IP_REGEX);\n    \n    /**\n     * Filter sensitive IP addresses.\n     * \n     * @param target IP addresses to be filtered\n     * @return filtered IP addresses\n     */\n    public static List<String> filterSensitiveIps(final List<String> target) {\n        final Map<String, String> fakeIpMap = new HashMap<>();\n        final AtomicInteger step = new AtomicInteger();\n        return target.stream().map(input -> {\n            Matcher matcher = IP_PATTERN.matcher(input);\n            String result = input;\n            while (matcher.find()) {\n                String realIp = matcher.group();\n                String fakeIp;\n                if (fakeIpMap.containsKey(realIp)) {\n                    fakeIp = fakeIpMap.get(realIp);\n                } else {\n                    fakeIp = FAKE_IP_SAMPLE + step.incrementAndGet();\n                    fakeIpMap.put(realIp, fakeIp);\n                }\n                result = result.replace(realIp, fakeIp);\n            }\n            return result;\n        }).collect(Collectors.toList());\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/yaml/YamlEngine.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.yaml;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.representer.ElasticJobYamlRepresenter;\nimport org.yaml.snakeyaml.DumperOptions;\nimport org.yaml.snakeyaml.LoaderOptions;\nimport org.yaml.snakeyaml.Yaml;\n\n/**\n * YAML engine.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class YamlEngine {\n    \n    /**\n     * Marshal YAML.\n     *\n     * @param value object to be marshaled\n     * @return YAML content\n     */\n    public static String marshal(final Object value) {\n        return new Yaml(new ElasticJobYamlRepresenter(new DumperOptions())).dumpAsMap(value);\n    }\n    \n    /**\n     * Unmarshal YAML.\n     *\n     * @param yamlContent YAML content\n     * @param classType class type\n     * @param <T> type of class\n     * @return object from YAML\n     */\n    public static <T> T unmarshal(final String yamlContent, final Class<T> classType) {\n        LoaderOptions loaderOptions = new LoaderOptions();\n        loaderOptions.setTagInspector(tagInspector -> tagInspector.getClassName().startsWith(\"org.apache.shardingsphere.elasticjob\"));\n        return new Yaml(loaderOptions).loadAs(yamlContent, classType);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/yaml/representer/DefaultYamlTupleProcessor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.yaml.representer;\n\nimport org.yaml.snakeyaml.nodes.CollectionNode;\nimport org.yaml.snakeyaml.nodes.MappingNode;\nimport org.yaml.snakeyaml.nodes.Node;\nimport org.yaml.snakeyaml.nodes.NodeTuple;\nimport org.yaml.snakeyaml.nodes.SequenceNode;\nimport org.yaml.snakeyaml.nodes.Tag;\n\n/**\n * Default YAML tuple processor. \n */\npublic final class DefaultYamlTupleProcessor {\n    \n    /**\n     * Process node tuple.\n     * \n     * @param nodeTuple node tuple\n     * @return processed node tuple\n     */\n    public NodeTuple process(final NodeTuple nodeTuple) {\n        return isUnsetNodeTuple(nodeTuple.getValueNode()) ? null : nodeTuple;\n    }\n    \n    private boolean isUnsetNodeTuple(final Node valueNode) {\n        return isNullNode(valueNode) || isEmptyCollectionNode(valueNode);\n    }\n    \n    private boolean isNullNode(final Node valueNode) {\n        return Tag.NULL.equals(valueNode.getTag());\n    }\n    \n    private boolean isEmptyCollectionNode(final Node valueNode) {\n        return valueNode instanceof CollectionNode && (isEmptySequenceNode(valueNode) || isEmptyMappingNode(valueNode));\n    }\n    \n    private boolean isEmptySequenceNode(final Node valueNode) {\n        return Tag.SEQ.equals(valueNode.getTag()) && ((SequenceNode) valueNode).getValue().isEmpty();\n    }\n    \n    private boolean isEmptyMappingNode(final Node valueNode) {\n        return Tag.MAP.equals(valueNode.getTag()) && ((MappingNode) valueNode).getValue().isEmpty();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/infra/yaml/representer/ElasticJobYamlRepresenter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.yaml.representer;\n\nimport org.yaml.snakeyaml.DumperOptions;\nimport org.yaml.snakeyaml.introspector.Property;\nimport org.yaml.snakeyaml.nodes.NodeTuple;\nimport org.yaml.snakeyaml.nodes.Tag;\nimport org.yaml.snakeyaml.representer.Representer;\n\n/**\n * ElasticJob YAML representer.\n */\npublic final class ElasticJobYamlRepresenter extends Representer {\n    \n    public ElasticJobYamlRepresenter(final DumperOptions options) {\n        super(options);\n    }\n    \n    @Override\n    protected NodeTuple representJavaBeanProperty(final Object javaBean, final Property property, final Object propertyValue, final Tag customTag) {\n        return new DefaultYamlTupleProcessor().process(super.representJavaBeanProperty(javaBean, property, propertyValue, customTag));\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/annotation/JobAnnotationBuilder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.annotation;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobConfiguration;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobProp;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.api.JobExtraConfiguration;\nimport org.apache.shardingsphere.elasticjob.api.JobExtraConfigurationFactory;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\n\nimport java.util.Optional;\n\n/**\n * Job Builder from @ElasticJobConfiguration.\n */\npublic final class JobAnnotationBuilder {\n    \n    /**\n     * Generate job configuration from @ElasticJobConfiguration.\n     * \n     * @param type The job of @ElasticJobConfiguration annotation class\n     * @return job configuration\n     */\n    public static JobConfiguration generateJobConfiguration(final Class<?> type) {\n        ElasticJobConfiguration annotation = type.getAnnotation(ElasticJobConfiguration.class);\n        Preconditions.checkArgument(null != annotation, \"@ElasticJobConfiguration not found by class '%s'.\", type);\n        Preconditions.checkArgument(!Strings.isNullOrEmpty(annotation.jobName()), \"@ElasticJobConfiguration jobName could not be empty by class '%s'.\", type);\n        JobConfiguration.Builder jobConfigurationBuilder = JobConfiguration.newBuilder(annotation.jobName(), annotation.shardingTotalCount())\n                .shardingItemParameters(annotation.shardingItemParameters())\n                .cron(Strings.isNullOrEmpty(annotation.cron()) ? null : annotation.cron())\n                .timeZone(Strings.isNullOrEmpty(annotation.timeZone()) ? null : annotation.timeZone())\n                .jobParameter(annotation.jobParameter())\n                .monitorExecution(annotation.monitorExecution())\n                .failover(annotation.failover())\n                .misfire(annotation.misfire())\n                .maxTimeDiffSeconds(annotation.maxTimeDiffSeconds())\n                .reconcileIntervalMinutes(annotation.reconcileIntervalMinutes())\n                .jobShardingStrategyType(Strings.isNullOrEmpty(annotation.jobShardingStrategyType()) ? null : annotation.jobShardingStrategyType())\n                .jobExecutorThreadPoolSizeProviderType(Strings.isNullOrEmpty(annotation.jobExecutorThreadPoolSizeProviderType()) ? null : annotation.jobExecutorThreadPoolSizeProviderType())\n                .jobErrorHandlerType(Strings.isNullOrEmpty(annotation.jobErrorHandlerType()) ? null : annotation.jobErrorHandlerType())\n                .jobListenerTypes(annotation.jobListenerTypes())\n                .description(annotation.description())\n                .disabled(annotation.disabled())\n                .overwrite(annotation.overwrite());\n        for (Class<? extends JobExtraConfigurationFactory> clazz : annotation.extraConfigurations()) {\n            try {\n                Optional<JobExtraConfiguration> jobExtraConfig = clazz.newInstance().getJobExtraConfiguration();\n                jobExtraConfig.ifPresent(jobConfigurationBuilder::addExtraConfigurations);\n            } catch (IllegalAccessException | InstantiationException exception) {\n                throw (JobConfigurationException) new JobConfigurationException(\"new JobExtraConfigurationFactory instance by class '%s' failure\", clazz).initCause(exception);\n            }\n        }\n        for (ElasticJobProp prop : annotation.props()) {\n            jobConfigurationBuilder.setProperty(prop.key(), prop.value());\n        }\n        return jobConfigurationBuilder.build();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/config/ConfigurationNode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.config;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\n\n/**\n * Configuration node.\n */\npublic final class ConfigurationNode {\n    \n    static final String ROOT = \"config\";\n    \n    private final JobNodePath jobNodePath;\n    \n    public ConfigurationNode(final String jobName) {\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    /**\n     * Judge is configuration root path or not.\n     * \n     * @param path node path\n     * @return is configuration root path or not\n     */\n    public boolean isConfigPath(final String path) {\n        return jobNodePath.getConfigNodePath().equals(path);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/config/ConfigurationService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.config;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionEnvironmentException;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.time.TimeService;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\n\n/**\n * Configuration service.\n */\npublic final class ConfigurationService {\n    \n    private final TimeService timeService;\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    public ConfigurationService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        timeService = new TimeService();\n    }\n    \n    /**\n     * Load job configuration.\n     * \n     * @param fromCache load from cache or not\n     * @return job configuration\n     */\n    public JobConfiguration load(final boolean fromCache) {\n        String result;\n        if (fromCache) {\n            result = jobNodeStorage.getJobNodeData(ConfigurationNode.ROOT);\n            if (null == result) {\n                result = jobNodeStorage.getJobNodeDataDirectly(ConfigurationNode.ROOT);\n            }\n        } else {\n            result = jobNodeStorage.getJobNodeDataDirectly(ConfigurationNode.ROOT);\n        }\n        if (result != null) {\n            return YamlEngine.unmarshal(result, JobConfigurationPOJO.class).toJobConfiguration();\n        } else {\n            throw new JobConfigurationException(\"JobConfiguration was not found. It maybe has been removed or has not been configured correctly.\");\n        }\n    }\n    \n    /**\n     * Set up job configuration.\n     * \n     * @param jobClassName job class name\n     * @param jobConfig job configuration to be updated\n     * @return accepted job configuration\n     */\n    public JobConfiguration setUpJobConfiguration(final String jobClassName, final JobConfiguration jobConfig) {\n        checkConflictJob(jobClassName, jobConfig);\n        if (!jobNodeStorage.isJobNodeExisted(ConfigurationNode.ROOT) || jobConfig.isOverwrite()) {\n            jobNodeStorage.replaceJobNode(ConfigurationNode.ROOT, YamlEngine.marshal(JobConfigurationPOJO.fromJobConfiguration(jobConfig)));\n            jobNodeStorage.replaceJobRootNode(jobClassName);\n            return jobConfig;\n        }\n        return load(false);\n    }\n    \n    private void checkConflictJob(final String newJobClassName, final JobConfiguration jobConfig) {\n        if (!jobNodeStorage.isJobRootNodeExisted()) {\n            return;\n        }\n        String originalJobClassName = jobNodeStorage.getJobRootNodeData();\n        if (StringUtils.isNotBlank(originalJobClassName) && !originalJobClassName.equals(newJobClassName)) {\n            throw new JobConfigurationException(\n                    \"Job conflict with register center. The job '%s' in register center's class is '%s', your job class is '%s'\", jobConfig.getJobName(), originalJobClassName, newJobClassName);\n        }\n    }\n    \n    /**\n     * Check max time different seconds tolerable between job server and registry center.\n     * \n     * @throws JobExecutionEnvironmentException throe JobExecutionEnvironmentException if exceed max time different seconds\n     */\n    public void checkMaxTimeDiffSecondsTolerable() throws JobExecutionEnvironmentException {\n        int maxTimeDiffSeconds = load(true).getMaxTimeDiffSeconds();\n        if (0 > maxTimeDiffSeconds) {\n            return;\n        }\n        long timeDiff = Math.abs(timeService.getCurrentMillis() - jobNodeStorage.getRegistryCenterTime());\n        if (timeDiff > maxTimeDiffSeconds * 1000L) {\n            throw new JobExecutionEnvironmentException(\n                    \"Time different between job server and register center exceed '%s' seconds, max time different is '%s' seconds.\", timeDiff / 1000, maxTimeDiffSeconds);\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/config/JobConfigurationPOJO.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.config;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.api.JobExtraConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfigurationConverter;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedList;\nimport java.util.Properties;\n\n/**\n * Job configuration POJO.\n */\n@Getter\n@Setter\npublic final class JobConfigurationPOJO {\n    \n    private String jobName;\n    \n    private String cron;\n    \n    private String timeZone;\n    \n    private int shardingTotalCount;\n    \n    private String shardingItemParameters;\n    \n    private String jobParameter;\n    \n    private boolean monitorExecution;\n    \n    private boolean failover;\n    \n    private boolean misfire;\n    \n    private int maxTimeDiffSeconds = -1;\n    \n    private int reconcileIntervalMinutes;\n    \n    private String jobShardingStrategyType;\n    \n    private String jobExecutorThreadPoolSizeProviderType;\n    \n    private String jobErrorHandlerType;\n    \n    private Collection<String> jobListenerTypes = new ArrayList<>();\n    \n    private Collection<YamlConfiguration<JobExtraConfiguration>> jobExtraConfigurations = new LinkedList<>();\n    \n    private String description;\n    \n    private Properties props = new Properties();\n    \n    private boolean disabled;\n    \n    private boolean overwrite;\n    \n    private String label;\n    \n    private boolean staticSharding;\n    \n    /**\n     * Convert to job configuration.\n     *\n     * @return job configuration\n     */\n    public JobConfiguration toJobConfiguration() {\n        JobConfiguration result = JobConfiguration.newBuilder(jobName, shardingTotalCount)\n                .cron(cron).timeZone(timeZone).shardingItemParameters(shardingItemParameters).jobParameter(jobParameter)\n                .monitorExecution(monitorExecution).failover(failover).misfire(misfire)\n                .maxTimeDiffSeconds(maxTimeDiffSeconds).reconcileIntervalMinutes(reconcileIntervalMinutes)\n                .jobShardingStrategyType(jobShardingStrategyType).jobExecutorThreadPoolSizeProviderType(jobExecutorThreadPoolSizeProviderType)\n                .jobErrorHandlerType(jobErrorHandlerType).jobListenerTypes(jobListenerTypes.toArray(new String[]{})).description(description)\n                .disabled(disabled).overwrite(overwrite).label(label).staticSharding(staticSharding).build();\n        jobExtraConfigurations.stream().map(YamlConfiguration::toConfiguration).forEach(result.getExtraConfigurations()::add);\n        for (Object each : props.keySet()) {\n            result.getProps().setProperty(each.toString(), props.get(each.toString()).toString());\n        }\n        return result;\n    }\n    \n    /**\n     * Convert from job configuration.\n     *\n     * @param jobConfig job configuration\n     * @return job configuration POJO\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static JobConfigurationPOJO fromJobConfiguration(final JobConfiguration jobConfig) {\n        JobConfigurationPOJO result = new JobConfigurationPOJO();\n        result.setJobName(jobConfig.getJobName());\n        result.setCron(jobConfig.getCron());\n        result.setTimeZone(jobConfig.getTimeZone());\n        result.setShardingTotalCount(jobConfig.getShardingTotalCount());\n        result.setShardingItemParameters(jobConfig.getShardingItemParameters());\n        result.setJobParameter(jobConfig.getJobParameter());\n        result.setMonitorExecution(jobConfig.isMonitorExecution());\n        result.setFailover(jobConfig.isFailover());\n        result.setMisfire(jobConfig.isMisfire());\n        result.setMaxTimeDiffSeconds(jobConfig.getMaxTimeDiffSeconds());\n        result.setReconcileIntervalMinutes(jobConfig.getReconcileIntervalMinutes());\n        result.setJobShardingStrategyType(jobConfig.getJobShardingStrategyType());\n        result.setJobExecutorThreadPoolSizeProviderType(jobConfig.getJobExecutorThreadPoolSizeProviderType());\n        result.setJobErrorHandlerType(jobConfig.getJobErrorHandlerType());\n        result.setJobListenerTypes(jobConfig.getJobListenerTypes());\n        jobConfig.getExtraConfigurations().stream()\n                .map(each -> TypedSPILoader.getService(YamlConfigurationConverter.class, each.getClass()).convertToYamlConfiguration(each)).forEach(result.getJobExtraConfigurations()::add);\n        result.setDescription(jobConfig.getDescription());\n        result.setProps(jobConfig.getProps());\n        result.setDisabled(jobConfig.isDisabled());\n        result.setOverwrite(jobConfig.isOverwrite());\n        result.setLabel(jobConfig.getLabel());\n        result.setStaticSharding(jobConfig.isStaticSharding());\n        return result;\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/config/RescheduleListenerManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.config;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.AbstractListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\n/**\n * Reschedule listener manager.\n */\npublic final class RescheduleListenerManager extends AbstractListenerManager {\n    \n    private final ConfigurationNode configNode;\n    \n    private final String jobName;\n    \n    public RescheduleListenerManager(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        super(regCenter, jobName);\n        this.jobName = jobName;\n        configNode = new ConfigurationNode(jobName);\n    }\n    \n    @Override\n    public void start() {\n        addDataListener(new CronSettingAndJobEventChangedJobListener());\n    }\n    \n    class CronSettingAndJobEventChangedJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (configNode.isConfigPath(event.getKey()) && Type.UPDATED == event.getType() && !JobRegistry.getInstance().isShutdown(jobName)) {\n                JobConfiguration jobConfig = YamlEngine.unmarshal(event.getValue(), JobConfigurationPOJO.class).toJobConfiguration();\n                if (StringUtils.isEmpty(jobConfig.getCron())) {\n                    JobRegistry.getInstance().getJobScheduleController(jobName).rescheduleJob();\n                } else {\n                    JobRegistry.getInstance().getJobScheduleController(jobName).rescheduleJob(jobConfig.getCron(), jobConfig.getTimeZone());\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/context/TaskContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.context;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Splitter;\nimport lombok.EqualsAndHashCode;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.Setter;\nimport lombok.ToString;\nimport org.apache.shardingsphere.elasticjob.spi.executor.ExecutionType;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.stream.Collectors;\n\n/**\n * Task runtime context.\n */\n@Getter\n@EqualsAndHashCode(of = \"id\")\n@ToString(of = \"id\")\npublic final class TaskContext {\n    \n    private static final String DELIMITER = \"@-@\";\n    \n    private static final String UNASSIGNED_SLAVE_ID = \"unassigned-slave\";\n    \n    private String id;\n    \n    private final MetaInfo metaInfo;\n    \n    private final ExecutionType type;\n    \n    private String slaveId;\n    \n    @Setter\n    private boolean idle;\n    \n    public TaskContext(final String jobName, final List<Integer> shardingItem, final ExecutionType type) {\n        this(jobName, shardingItem, type, UNASSIGNED_SLAVE_ID);\n    }\n    \n    public TaskContext(final String jobName, final List<Integer> shardingItem, final ExecutionType type, final String slaveId) {\n        metaInfo = new MetaInfo(jobName, shardingItem);\n        this.type = type;\n        this.slaveId = slaveId;\n        id = String.join(DELIMITER, metaInfo.toString(), type.toString(), slaveId, UUID.randomUUID().toString());\n    }\n    \n    private TaskContext(final String id, final MetaInfo metaInfo, final ExecutionType type, final String slaveId) {\n        this.id = id;\n        this.metaInfo = metaInfo;\n        this.type = type;\n        this.slaveId = slaveId;\n    }\n    \n    /**\n     * Get task context via task ID.\n     *\n     * @param id task ID\n     * @return task context\n     */\n    public static TaskContext from(final String id) {\n        String[] result = id.split(DELIMITER);\n        Preconditions.checkState(5 == result.length);\n        return new TaskContext(id, MetaInfo.from(result[0] + DELIMITER + result[1]), ExecutionType.valueOf(result[2]), result[3]);\n    }\n    \n    /**\n     * Get unassigned task ID before job execute.\n     *\n     * @param id task ID\n     * @return unassigned task ID before job execute\n     */\n    public static String getIdForUnassignedSlave(final String id) {\n        return id.replaceAll(TaskContext.from(id).getSlaveId(), UNASSIGNED_SLAVE_ID);\n    }\n    \n    /**\n     * Set job server ID.\n     *\n     * @param slaveId job server ID\n     */\n    public void setSlaveId(final String slaveId) {\n        id = id.replaceAll(this.slaveId, slaveId);\n        this.slaveId = slaveId;\n    }\n    \n    /**\n     * Get task name.\n     *\n     * @return task name\n     */\n    public String getTaskName() {\n        return String.join(DELIMITER, metaInfo.toString(), type.toString(), slaveId);\n    }\n    \n    /**\n     * Get executor ID.\n     *\n     * @param appName application name\n     * @return executor ID\n     */\n    public String getExecutorId(final String appName) {\n        return String.join(DELIMITER, appName, slaveId);\n    }\n    \n    /**\n     * Task meta data.\n     */\n    @RequiredArgsConstructor\n    @Getter\n    @EqualsAndHashCode\n    public static class MetaInfo {\n        \n        private final String jobName;\n        \n        private final List<Integer> shardingItems;\n        \n        /**\n         * Get task meta data info via string.\n         *\n         * @param value task meta data info string\n         * @return task meta data info\n         */\n        public static MetaInfo from(final String value) {\n            String[] result = value.split(DELIMITER);\n            Preconditions.checkState(1 == result.length || 2 == result.length || 5 == result.length);\n            return new MetaInfo(result[0], 1 == result.length || \"\".equals(result[1])\n                    ? Collections.emptyList()\n                    : Splitter.on(\",\").splitToList(result[1]).stream().map(Integer::parseInt).collect(Collectors.toList()));\n        }\n        \n        @Override\n        public final String toString() {\n            return String.join(DELIMITER, jobName, shardingItems.stream().map(Object::toString).collect(Collectors.joining(\",\")));\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/election/ElectionListenerManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.election;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.AbstractListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerStatus;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\nimport java.util.Objects;\n\n/**\n * Election listener manager.\n */\npublic final class ElectionListenerManager extends AbstractListenerManager {\n    \n    private final String jobName;\n    \n    private final LeaderNode leaderNode;\n    \n    private final ServerNode serverNode;\n    \n    private final LeaderService leaderService;\n    \n    private final ServerService serverService;\n    \n    public ElectionListenerManager(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        super(regCenter, jobName);\n        this.jobName = jobName;\n        leaderNode = new LeaderNode(jobName);\n        serverNode = new ServerNode(jobName);\n        leaderService = new LeaderService(regCenter, jobName);\n        serverService = new ServerService(regCenter, jobName);\n    }\n    \n    @Override\n    public void start() {\n        addDataListener(new LeaderElectionJobListener());\n        addDataListener(new LeaderAbdicationJobListener());\n    }\n    \n    class LeaderElectionJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (!JobRegistry.getInstance().isShutdown(jobName) && (isActiveElection(event.getKey(), event.getValue()) || isPassiveElection(event.getKey(), event.getType()))) {\n                leaderService.electLeader();\n            }\n        }\n        \n        private boolean isActiveElection(final String path, final String data) {\n            return !leaderService.hasLeader() && isLocalServerEnabled(path, data);\n        }\n        \n        private boolean isPassiveElection(final String path, final Type eventType) {\n            JobInstance jobInstance = JobRegistry.getInstance().getJobInstance(jobName);\n            return !Objects.isNull(jobInstance) && isLeaderCrashed(path, eventType) && serverService.isAvailableServer(jobInstance.getServerIp());\n        }\n        \n        private boolean isLeaderCrashed(final String path, final Type eventType) {\n            return leaderNode.isLeaderInstancePath(path) && Type.DELETED == eventType;\n        }\n        \n        private boolean isLocalServerEnabled(final String path, final String data) {\n            return serverNode.isLocalServerPath(path) && !ServerStatus.DISABLED.name().equals(data);\n        }\n    }\n    \n    class LeaderAbdicationJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (leaderService.isLeader() && isLocalServerDisabled(event.getKey(), event.getValue())) {\n                leaderService.removeLeader();\n            }\n        }\n        \n        private boolean isLocalServerDisabled(final String path, final String data) {\n            return serverNode.isLocalServerPath(path) && ServerStatus.DISABLED.name().equals(data);\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/election/LeaderNode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.election;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\n\n/**\n * Leader path node.\n */\npublic final class LeaderNode {\n    \n    public static final String ROOT = \"leader\";\n    \n    private static final String ELECTION_ROOT = ROOT + \"/election\";\n    \n    static final String INSTANCE = ELECTION_ROOT + \"/instance\";\n    \n    static final String LATCH = ELECTION_ROOT + \"/latch\";\n    \n    private final JobNodePath jobNodePath;\n    \n    LeaderNode(final String jobName) {\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    boolean isLeaderInstancePath(final String path) {\n        return jobNodePath.getFullPath(INSTANCE).equals(path);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/election/LeaderService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.election;\n\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.reg.base.LeaderExecutionCallback;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.util.BlockUtils;\n\n/**\n * Leader service.\n */\n@Slf4j\npublic final class LeaderService {\n    \n    private final String jobName;\n    \n    private final ServerService serverService;\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    public LeaderService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        this.jobName = jobName;\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        serverService = new ServerService(regCenter, jobName);\n    }\n    \n    /**\n     * Elect leader.\n     */\n    public void electLeader() {\n        log.debug(\"Elect a new leader now.\");\n        jobNodeStorage.executeInLeader(LeaderNode.LATCH, new LeaderElectionExecutionCallback());\n        log.debug(\"Leader election completed.\");\n    }\n    \n    /**\n     * Judge current server is leader or not.\n     * \n     * <p>\n     * If leader is electing, this method will block until leader elected success.\n     * </p>\n     * \n     * @return current server is leader or not\n     */\n    public boolean isLeaderUntilBlock() {\n        while (!hasLeader() && serverService.hasAvailableServers()) {\n            log.info(\"Leader is electing, waiting for {} ms\", 100);\n            BlockUtils.waitingShortTime();\n            if (!JobRegistry.getInstance().isShutdown(jobName) && serverService.isAvailableServer(JobRegistry.getInstance().getJobInstance(jobName).getServerIp())) {\n                electLeader();\n            }\n        }\n        return isLeader();\n    }\n    \n    /**\n     * Judge current server is leader or not.\n     *\n     * @return current server is leader or not\n     */\n    public boolean isLeader() {\n        return !JobRegistry.getInstance().isShutdown(jobName) && JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId().equals(jobNodeStorage.getJobNodeData(LeaderNode.INSTANCE));\n    }\n    \n    /**\n     * Judge has leader or not in current time.\n     * \n     * @return has leader or not in current time\n     */\n    public boolean hasLeader() {\n        return jobNodeStorage.isJobNodeExisted(LeaderNode.INSTANCE);\n    }\n    \n    /**\n     * Remove leader and trigger leader election.\n     */\n    public void removeLeader() {\n        jobNodeStorage.removeJobNodeIfExisted(LeaderNode.INSTANCE);\n    }\n    \n    @RequiredArgsConstructor\n    class LeaderElectionExecutionCallback implements LeaderExecutionCallback {\n        \n        @Override\n        public void execute() {\n            if (!hasLeader()) {\n                jobNodeStorage.fillEphemeralJobNode(LeaderNode.INSTANCE, JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/failover/FailoverListenerManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.failover;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.AbstractListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\n/**\n * Failover listener manager.\n */\npublic final class FailoverListenerManager extends AbstractListenerManager {\n    \n    private final String jobName;\n    \n    private final ConfigurationService configService;\n    \n    private final ShardingService shardingService;\n    \n    private final FailoverService failoverService;\n    \n    private final ExecutionService executionService;\n    \n    private final InstanceService instanceService;\n    \n    private final ConfigurationNode configNode;\n    \n    private final InstanceNode instanceNode;\n    \n    public FailoverListenerManager(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        super(regCenter, jobName);\n        this.jobName = jobName;\n        configService = new ConfigurationService(regCenter, jobName);\n        shardingService = new ShardingService(regCenter, jobName);\n        failoverService = new FailoverService(regCenter, jobName);\n        executionService = new ExecutionService(regCenter, jobName);\n        instanceService = new InstanceService(regCenter, jobName);\n        configNode = new ConfigurationNode(jobName);\n        instanceNode = new InstanceNode(jobName);\n    }\n    \n    @Override\n    public void start() {\n        addDataListener(new JobCrashedJobListener());\n        addDataListener(new FailoverSettingsChangedJobListener());\n        addDataListener(new LegacyCrashedRunningItemListener());\n    }\n    \n    private boolean isFailoverEnabled() {\n        return configService.load(true).isFailover();\n    }\n    \n    class JobCrashedJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (!JobRegistry.getInstance().isShutdown(jobName) && isFailoverEnabled() && Type.DELETED == event.getType() && instanceNode.isInstancePath(event.getKey())) {\n                String jobInstanceId = event.getKey().substring(instanceNode.getInstanceFullPath().length() + 1);\n                if (jobInstanceId.equals(JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId())) {\n                    return;\n                }\n                List<Integer> failoverItems = failoverService.getFailoveringItems(jobInstanceId);\n                if (!failoverItems.isEmpty()) {\n                    for (int each : failoverItems) {\n                        failoverService.setCrashedFailoverFlagDirectly(each);\n                        executionService.clearRunningInfo(Collections.singletonList(each));\n                        failoverService.failoverIfNecessary();\n                    }\n                } else {\n                    for (int each : shardingService.getCrashedShardingItems(jobInstanceId)) {\n                        failoverService.setCrashedFailoverFlag(each);\n                        failoverService.failoverIfNecessary();\n                    }\n                }\n            }\n        }\n    }\n    \n    class FailoverSettingsChangedJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (configNode.isConfigPath(event.getKey()) && Type.UPDATED == event.getType() && !YamlEngine.unmarshal(event.getValue(), JobConfigurationPOJO.class).toJobConfiguration().isFailover()) {\n                failoverService.removeFailoverInfo();\n            }\n        }\n    }\n    \n    class LegacyCrashedRunningItemListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (!isCurrentInstanceOnline(event) || !isFailoverEnabled()) {\n                return;\n            }\n            Set<JobInstance> availableJobInstances = new HashSet<>(instanceService.getAvailableJobInstances());\n            if (!isTheOnlyInstance(availableJobInstances)) {\n                return;\n            }\n            Map<Integer, JobInstance> allRunningItems = executionService.getAllRunningItems();\n            Map<Integer, JobInstance> allFailoveringItems = failoverService.getAllFailoveringItems();\n            if (allRunningItems.isEmpty() && allFailoveringItems.isEmpty()) {\n                return;\n            }\n            for (Entry<Integer, JobInstance> entry : allFailoveringItems.entrySet()) {\n                if (!availableJobInstances.contains(entry.getValue())) {\n                    int item = entry.getKey();\n                    failoverService.setCrashedFailoverFlagDirectly(item);\n                    failoverService.clearFailoveringItem(item);\n                    executionService.clearRunningInfo(Collections.singletonList(item));\n                    allRunningItems.remove(item);\n                }\n            }\n            for (Entry<Integer, JobInstance> entry : allRunningItems.entrySet()) {\n                if (!availableJobInstances.contains(entry.getValue())) {\n                    failoverService.setCrashedFailoverFlag(entry.getKey());\n                    executionService.clearRunningInfo(Collections.singletonList(entry.getKey()));\n                }\n            }\n            failoverService.failoverIfNecessary();\n        }\n        \n        private boolean isCurrentInstanceOnline(final DataChangedEvent event) {\n            return Type.ADDED == event.getType() && !JobRegistry.getInstance().isShutdown(jobName) && event.getKey().endsWith(instanceNode.getLocalInstancePath());\n        }\n        \n        private boolean isTheOnlyInstance(final Set<JobInstance> availableJobInstances) {\n            return Collections.singleton(JobRegistry.getInstance().getJobInstance(jobName)).equals(availableJobInstances);\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/failover/FailoverNode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.failover;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\n\n/**\n * Failover node.\n */\npublic final class FailoverNode {\n    \n    private static final String FAILOVER = \"failover\";\n    \n    private static final String LEADER_ROOT = LeaderNode.ROOT + \"/\" + FAILOVER;\n    \n    static final String ITEMS_ROOT = LEADER_ROOT + \"/items\";\n    \n    private static final String ITEMS = ITEMS_ROOT + \"/%s\";\n    \n    static final String LATCH = LEADER_ROOT + \"/latch\";\n    \n    private static final String EXECUTION_FAILOVER = ShardingNode.ROOT + \"/%s/\" + FAILOVER;\n    \n    private static final String FAILOVERING = \"failovering\";\n    \n    private static final String EXECUTING_FAILOVER = ShardingNode.ROOT + \"/%s/\" + FAILOVERING;\n    \n    private final JobNodePath jobNodePath;\n    \n    public FailoverNode(final String jobName) {\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    static String getItemsNode(final int item) {\n        return String.format(ITEMS, item);\n    }\n    \n    static String getExecutionFailoverNode(final int item) {\n        return String.format(EXECUTION_FAILOVER, item);\n    }\n    \n    static String getExecutingFailoverNode(final int item) {\n        return String.format(EXECUTING_FAILOVER, item);\n    }\n    \n    /**\n     * Get sharding item by execution failover path.\n     *\n     * @param path failover path\n     * @return sharding item, return null if not from failover path\n     */\n    public Integer getItemByExecutionFailoverPath(final String path) {\n        if (!isFailoverPath(path)) {\n            return null;\n        }\n        return Integer.parseInt(path.substring(jobNodePath.getFullPath(ShardingNode.ROOT).length() + 1, path.lastIndexOf(FailoverNode.FAILOVER) - 1));\n    }\n    \n    private boolean isFailoverPath(final String path) {\n        return path.startsWith(jobNodePath.getFullPath(ShardingNode.ROOT)) && path.endsWith(FailoverNode.FAILOVER);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/failover/FailoverService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.failover;\n\nimport com.google.common.base.Strings;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.base.LeaderExecutionCallback;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Failover service.\n */\n@Slf4j\npublic final class FailoverService {\n    \n    private final String jobName;\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    private final ShardingService shardingService;\n    \n    private final ConfigurationService configService;\n    \n    public FailoverService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        this.jobName = jobName;\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        shardingService = new ShardingService(regCenter, jobName);\n        configService = new ConfigurationService(regCenter, jobName);\n    }\n    \n    /**\n     * set crashed failover flag.\n     * \n     * @param item crashed job item\n     */\n    public void setCrashedFailoverFlag(final int item) {\n        if (!isFailoverAssigned(item)) {\n            jobNodeStorage.createJobNodeIfNeeded(FailoverNode.getItemsNode(item));\n            jobNodeStorage.removeJobNodeIfExisted(ShardingNode.getRunningNode(item));\n        }\n    }\n    \n    /**\n     * set crashed failover flag directly.\n     *\n     * @param item crashed item\n     */\n    public void setCrashedFailoverFlagDirectly(final int item) {\n        jobNodeStorage.createJobNodeIfNeeded(FailoverNode.getItemsNode(item));\n    }\n    \n    private boolean isFailoverAssigned(final Integer item) {\n        return jobNodeStorage.isJobNodeExisted(FailoverNode.getExecutionFailoverNode(item));\n    }\n    \n    /**\n     * Failover if necessary.\n     */\n    public void failoverIfNecessary() {\n        if (needFailover()) {\n            jobNodeStorage.executeInLeader(FailoverNode.LATCH, new FailoverLeaderExecutionCallback());\n        }\n    }\n    \n    private boolean needFailover() {\n        return jobNodeStorage.isJobNodeExisted(FailoverNode.ITEMS_ROOT) && !jobNodeStorage.getJobNodeChildrenKeys(FailoverNode.ITEMS_ROOT).isEmpty()\n                && !JobRegistry.getInstance().isJobRunning(jobName);\n    }\n    \n    /**\n     * Update sharding items status when failover execution complete.\n     * \n     * @param items sharding items of failover execution completed\n     */\n    public void updateFailoverComplete(final Collection<Integer> items) {\n        for (int each : items) {\n            jobNodeStorage.removeJobNodeIfExisted(FailoverNode.getExecutionFailoverNode(each));\n            jobNodeStorage.removeJobNodeIfExisted(FailoverNode.getExecutingFailoverNode(each));\n        }\n    }\n    \n    /**\n     * Get failover items.\n     *\n     * @param jobInstanceId job instance ID\n     * @return failover items\n     */\n    public List<Integer> getFailoverItems(final String jobInstanceId) {\n        List<String> items = jobNodeStorage.getJobNodeChildrenKeys(ShardingNode.ROOT);\n        List<Integer> result = new ArrayList<>(items.size());\n        for (String each : items) {\n            int item = Integer.parseInt(each);\n            String node = FailoverNode.getExecutionFailoverNode(item);\n            if (jobNodeStorage.isJobNodeExisted(node) && jobInstanceId.equals(jobNodeStorage.getJobNodeDataDirectly(node))) {\n                result.add(item);\n            }\n        }\n        Collections.sort(result);\n        return result;\n    }\n    \n    /**\n     * Get failovering items.\n     *\n     * @param jobInstanceId job instance ID\n     * @return failovering items\n     */\n    public List<Integer> getFailoveringItems(final String jobInstanceId) {\n        List<String> items = jobNodeStorage.getJobNodeChildrenKeys(ShardingNode.ROOT);\n        List<Integer> result = new ArrayList<>(items.size());\n        for (String each : items) {\n            int item = Integer.parseInt(each);\n            String node = FailoverNode.getExecutingFailoverNode(item);\n            if (jobNodeStorage.isJobNodeExisted(node) && jobInstanceId.equals(jobNodeStorage.getJobNodeDataDirectly(node))) {\n                result.add(item);\n            }\n        }\n        Collections.sort(result);\n        return result;\n    }\n    \n    /**\n     * Get failover items which execute on localhost.\n     * \n     * @return failover items which execute on localhost\n     */\n    public List<Integer> getLocalFailoverItems() {\n        if (JobRegistry.getInstance().isShutdown(jobName)) {\n            return Collections.emptyList();\n        }\n        return getFailoverItems(JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId());\n    }\n    \n    /**\n     * Get failover items which crashed on localhost.\n     * \n     * @return failover items which crashed on localhost\n     */\n    public List<Integer> getLocalTakeOffItems() {\n        List<Integer> shardingItems = shardingService.getLocalShardingItems();\n        List<Integer> result = new ArrayList<>(shardingItems.size());\n        for (int each : shardingItems) {\n            if (jobNodeStorage.isJobNodeExisted(FailoverNode.getExecutionFailoverNode(each))) {\n                result.add(each);\n            }\n        }\n        return result;\n    }\n    \n    /**\n     * Get all failovering items.\n     *\n     * @return all failovering items\n     */\n    public Map<Integer, JobInstance> getAllFailoveringItems() {\n        int shardingTotalCount = configService.load(true).getShardingTotalCount();\n        Map<Integer, JobInstance> result = new LinkedHashMap<>(shardingTotalCount, 1);\n        for (int i = 0; i < shardingTotalCount; i++) {\n            String data = jobNodeStorage.getJobNodeData(FailoverNode.getExecutingFailoverNode(i));\n            if (!Strings.isNullOrEmpty(data)) {\n                result.put(i, new JobInstance(data));\n            }\n        }\n        return result;\n    }\n    \n    /**\n     * Clear failovering item.\n     *\n     * @param item item\n     */\n    public void clearFailoveringItem(final int item) {\n        jobNodeStorage.removeJobNodeIfExisted(FailoverNode.getExecutingFailoverNode(item));\n    }\n    \n    /**\n     * Remove failover info.\n     */\n    public void removeFailoverInfo() {\n        for (String each : jobNodeStorage.getJobNodeChildrenKeys(ShardingNode.ROOT)) {\n            jobNodeStorage.removeJobNodeIfExisted(FailoverNode.getExecutionFailoverNode(Integer.parseInt(each)));\n        }\n    }\n    \n    class FailoverLeaderExecutionCallback implements LeaderExecutionCallback {\n        \n        @Override\n        public void execute() {\n            if (JobRegistry.getInstance().isShutdown(jobName) || !needFailover()) {\n                return;\n            }\n            int crashedItem = Integer.parseInt(jobNodeStorage.getJobNodeChildrenKeys(FailoverNode.ITEMS_ROOT).get(0));\n            log.debug(\"Failover job '{}' begin, crashed item '{}'\", jobName, crashedItem);\n            jobNodeStorage.fillEphemeralJobNode(FailoverNode.getExecutionFailoverNode(crashedItem), JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId());\n            jobNodeStorage.fillJobNode(FailoverNode.getExecutingFailoverNode(crashedItem), JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId());\n            jobNodeStorage.removeJobNodeIfExisted(FailoverNode.getItemsNode(crashedItem));\n            // TODO Instead of using triggerJob, use executor for unified scheduling\n            JobScheduleController jobScheduleController = JobRegistry.getInstance().getJobScheduleController(jobName);\n            if (null != jobScheduleController) {\n                jobScheduleController.triggerJob();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/guarantee/GuaranteeListenerManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.guarantee;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.AbstractDistributeOnceElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.AbstractListenerManager;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\nimport java.util.Collection;\n\n/**\n * Guarantee listener manager.\n */\npublic final class GuaranteeListenerManager extends AbstractListenerManager {\n    \n    private final GuaranteeNode guaranteeNode;\n    \n    private final Collection<ElasticJobListener> elasticJobListeners;\n    \n    public GuaranteeListenerManager(final CoordinatorRegistryCenter regCenter, final String jobName, final Collection<ElasticJobListener> elasticJobListeners) {\n        super(regCenter, jobName);\n        this.guaranteeNode = new GuaranteeNode(jobName);\n        this.elasticJobListeners = elasticJobListeners;\n    }\n    \n    @Override\n    public void start() {\n        addDataListener(new StartedNodeRemovedJobListener());\n        addDataListener(new CompletedNodeRemovedJobListener());\n    }\n    \n    class StartedNodeRemovedJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (Type.DELETED == event.getType() && guaranteeNode.isStartedRootNode(event.getKey())) {\n                for (ElasticJobListener each : elasticJobListeners) {\n                    if (each instanceof AbstractDistributeOnceElasticJobListener) {\n                        ((AbstractDistributeOnceElasticJobListener) each).notifyWaitingTaskStart();\n                    }\n                }\n            }\n        }\n    }\n    \n    class CompletedNodeRemovedJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (Type.DELETED == event.getType() && guaranteeNode.isCompletedRootNode(event.getKey())) {\n                for (ElasticJobListener each : elasticJobListeners) {\n                    if (each instanceof AbstractDistributeOnceElasticJobListener) {\n                        ((AbstractDistributeOnceElasticJobListener) each).notifyWaitingTaskComplete();\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/guarantee/GuaranteeNode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.guarantee;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\n\n/**\n * Guarantee node.\n */\npublic final class GuaranteeNode {\n    \n    private static final String ROOT = \"guarantee\";\n    \n    static final String STARTED_ROOT = ROOT + \"/started\";\n    \n    static final String COMPLETED_ROOT = ROOT + \"/completed\";\n    \n    static final String STARTED_LATCH_ROOT = ROOT + \"/started-latch\";\n    \n    static final String COMPLETED_LATCH_ROOT = ROOT + \"/completed-latch\";\n    \n    private final JobNodePath jobNodePath;\n    \n    GuaranteeNode(final String jobName) {\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    static String getStartedNode(final int shardingItem) {\n        return String.join(\"/\", STARTED_ROOT, String.valueOf(shardingItem));\n    }\n    \n    static String getCompletedNode(final int shardingItem) {\n        return String.join(\"/\", COMPLETED_ROOT, String.valueOf(shardingItem));\n    }\n    \n    boolean isStartedRootNode(final String path) {\n        return jobNodePath.getFullPath(STARTED_ROOT).equals(path);\n    }\n    \n    boolean isCompletedRootNode(final String path) {\n        return jobNodePath.getFullPath(COMPLETED_ROOT).equals(path);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/guarantee/GuaranteeService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.guarantee;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.AbstractDistributeOnceElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.base.LeaderExecutionCallback;\n\nimport java.util.Collection;\n\n/**\n * Guarantee service.\n */\npublic final class GuaranteeService {\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    private final ConfigurationService configService;\n    \n    public GuaranteeService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        configService = new ConfigurationService(regCenter, jobName);\n    }\n    \n    /**\n     * Register start.\n     *\n     * @param shardingItems to be registered sharding items\n     */\n    public void registerStart(final Collection<Integer> shardingItems) {\n        for (int each : shardingItems) {\n            jobNodeStorage.createJobNodeIfNeeded(GuaranteeNode.getStartedNode(each));\n        }\n    }\n    \n    /**\n     * Judge whether current sharding items are all register start success.\n     *\n     * @param shardingItems current sharding items\n     * @return current sharding items are all start success or not\n     */\n    public boolean isRegisterStartSuccess(final Collection<Integer> shardingItems) {\n        for (int each : shardingItems) {\n            if (!jobNodeStorage.isJobNodeExisted(GuaranteeNode.getStartedNode(each))) {\n                return false;\n            }\n        }\n        return true;\n    }\n    \n    /**\n     * Judge whether job's sharding items are all started.\n     *\n     * @return job's sharding items are all started or not\n     */\n    public boolean isAllStarted() {\n        return jobNodeStorage.isJobNodeExisted(GuaranteeNode.STARTED_ROOT)\n                && configService.load(false).getShardingTotalCount() == jobNodeStorage.getJobNodeChildrenKeys(GuaranteeNode.STARTED_ROOT).size();\n    }\n    \n    /**\n     * Clear all started job's info.\n     */\n    public void clearAllStartedInfo() {\n        jobNodeStorage.removeJobNodeIfExisted(GuaranteeNode.STARTED_ROOT);\n    }\n    \n    /**\n     * Register complete.\n     *\n     * @param shardingItems to be registered sharding items\n     */\n    public void registerComplete(final Collection<Integer> shardingItems) {\n        for (int each : shardingItems) {\n            jobNodeStorage.createJobNodeIfNeeded(GuaranteeNode.getCompletedNode(each));\n        }\n    }\n    \n    /**\n     * Judge whether sharding items are register complete success.\n     *\n     * @param shardingItems current sharding items\n     * @return current sharding items are all complete success or not\n     */\n    public boolean isRegisterCompleteSuccess(final Collection<Integer> shardingItems) {\n        for (int each : shardingItems) {\n            if (!jobNodeStorage.isJobNodeExisted(GuaranteeNode.getCompletedNode(each))) {\n                return false;\n            }\n        }\n        return true;\n    }\n    \n    /**\n     * Judge whether job's sharding items are all completed.\n     *\n     * @return job's sharding items are all completed or not\n     */\n    public boolean isAllCompleted() {\n        return jobNodeStorage.isJobNodeExisted(GuaranteeNode.COMPLETED_ROOT)\n                && configService.load(false).getShardingTotalCount() <= jobNodeStorage.getJobNodeChildrenKeys(GuaranteeNode.COMPLETED_ROOT).size();\n    }\n    \n    /**\n     * Clear all completed job's info.\n     */\n    public void clearAllCompletedInfo() {\n        jobNodeStorage.removeJobNodeIfExisted(GuaranteeNode.COMPLETED_ROOT);\n    }\n    \n    /**\n     * Invoke doBeforeJobExecutedAtLastStarted method once after last started.\n     *\n     * @param listener         AbstractDistributeOnceElasticJobListener instance\n     * @param shardingContexts sharding contexts\n     */\n    public void executeInLeaderForLastStarted(final AbstractDistributeOnceElasticJobListener listener,\n                                              final ShardingContexts shardingContexts) {\n        jobNodeStorage.executeInLeader(GuaranteeNode.STARTED_LATCH_ROOT,\n                new LeaderExecutionCallbackForLastStarted(listener, shardingContexts));\n    }\n    \n    /**\n     * Invoke doAfterJobExecutedAtLastCompleted method once after last completed.\n     *\n     * @param listener         AbstractDistributeOnceElasticJobListener instance\n     * @param shardingContexts sharding contexts\n     */\n    public void executeInLeaderForLastCompleted(final AbstractDistributeOnceElasticJobListener listener,\n                                                final ShardingContexts shardingContexts) {\n        jobNodeStorage.executeInLeader(GuaranteeNode.COMPLETED_LATCH_ROOT,\n                new LeaderExecutionCallbackForLastCompleted(listener, shardingContexts));\n    }\n    \n    /**\n     * Inner class for last started callback.\n     */\n    @RequiredArgsConstructor\n    class LeaderExecutionCallbackForLastStarted implements LeaderExecutionCallback {\n        \n        private final AbstractDistributeOnceElasticJobListener listener;\n        \n        private final ShardingContexts shardingContexts;\n        \n        @Override\n        public void execute() {\n            try {\n                if (!isAllStarted()) {\n                    return;\n                }\n                listener.doBeforeJobExecutedAtLastStarted(shardingContexts);\n            } finally {\n                clearAllStartedInfo();\n            }\n        }\n    }\n    \n    /**\n     * Inner class for last completed callback.\n     */\n    @RequiredArgsConstructor\n    class LeaderExecutionCallbackForLastCompleted implements LeaderExecutionCallback {\n        \n        private final AbstractDistributeOnceElasticJobListener listener;\n        \n        private final ShardingContexts shardingContexts;\n        \n        @Override\n        public void execute() {\n            try {\n                if (!isAllCompleted()) {\n                    return;\n                }\n                listener.doAfterJobExecutedAtLastCompleted(shardingContexts);\n            } finally {\n                clearAllCompletedInfo();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/instance/InstanceNode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.instance;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\n\n/**\n * Instance node.\n */\npublic final class InstanceNode {\n    \n    public static final String ROOT = \"instances\";\n    \n    private static final String INSTANCES = ROOT + \"/%s\";\n    \n    private final String jobName;\n    \n    private final JobNodePath jobNodePath;\n    \n    public InstanceNode(final String jobName) {\n        this.jobName = jobName;\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    /**\n     * Get job instance full path.\n     *\n     * @return job instance full path\n     */\n    public String getInstanceFullPath() {\n        return jobNodePath.getFullPath(InstanceNode.ROOT);\n    }\n    \n    /**\n     * Judge path is job instance path or not.\n     *\n     * @param path path to be judged\n     * @return path is job instance path or not\n     */\n    public boolean isInstancePath(final String path) {\n        return path.startsWith(jobNodePath.getFullPath(InstanceNode.ROOT));\n    }\n    \n    boolean isLocalInstancePath(final String path) {\n        return path.equals(jobNodePath.getFullPath(String.format(INSTANCES, JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId())));\n    }\n    \n    /**\n     * Get local instance path.\n     *\n     * @return local instance path\n     */\n    public String getLocalInstancePath() {\n        return getInstancePath(JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId());\n    }\n    \n    /**\n     * Get local instance value.\n     *\n     * @return local instance value\n     */\n    public String getLocalInstanceValue() {\n        return YamlEngine.marshal(JobRegistry.getInstance().getJobInstance(jobName));\n    }\n    \n    /**\n     * Get instance path.\n     *\n     * @param instanceId instance id\n     * @return instance path\n     */\n    public String getInstancePath(final String instanceId) {\n        return String.format(INSTANCES, instanceId);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/instance/InstanceService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.instance;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.trigger.TriggerNode;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\n/**\n * Job instance service.\n */\npublic final class InstanceService {\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    private final InstanceNode instanceNode;\n    \n    private final TriggerNode triggerNode;\n    \n    private final ServerService serverService;\n    \n    public InstanceService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        instanceNode = new InstanceNode(jobName);\n        triggerNode = new TriggerNode(jobName);\n        serverService = new ServerService(regCenter, jobName);\n    }\n    \n    /**\n     * Persist job online status.\n     */\n    public void persistOnline() {\n        jobNodeStorage.fillEphemeralJobNode(instanceNode.getLocalInstancePath(), instanceNode.getLocalInstanceValue());\n    }\n    \n    /**\n     * Persist job instance.\n     */\n    public void removeInstance() {\n        jobNodeStorage.removeJobNodeIfExisted(instanceNode.getLocalInstancePath());\n    }\n    \n    /**\n     * Get available job instances.\n     *\n     * @return available job instances\n     */\n    public List<JobInstance> getAvailableJobInstances() {\n        List<JobInstance> result = new LinkedList<>();\n        for (String each : jobNodeStorage.getJobNodeChildrenKeys(InstanceNode.ROOT)) {\n            // TODO It's better to make it atomic\n            String jobNodeData = jobNodeStorage.getJobNodeData(instanceNode.getInstancePath(each));\n            if (null == jobNodeData) {\n                continue;\n            }\n            JobInstance jobInstance = YamlEngine.unmarshal(jobNodeData, JobInstance.class);\n            if (null != jobInstance && serverService.isEnableServer(jobInstance.getServerIp())) {\n                result.add(jobInstance);\n            }\n        }\n        return result;\n    }\n    \n    boolean isLocalJobInstanceExisted() {\n        return jobNodeStorage.isJobNodeExisted(instanceNode.getLocalInstancePath());\n    }\n    \n    /**\n     * Trigger all instances.\n     */\n    public void triggerAllInstances() {\n        jobNodeStorage.removeJobNodeIfExisted(triggerNode.getTriggerRoot());\n        jobNodeStorage.getJobNodeChildrenKeys(InstanceNode.ROOT).forEach(each -> jobNodeStorage.createJobNodeIfNeeded(triggerNode.getTriggerPath(each)));\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/instance/ShutdownListenerManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.instance;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.AbstractListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.SchedulerFacade;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\n/**\n * Job instance shutdown listener manager.\n */\npublic final class ShutdownListenerManager extends AbstractListenerManager {\n    \n    private final String jobName;\n    \n    private final InstanceNode instanceNode;\n    \n    private final InstanceService instanceService;\n    \n    private final SchedulerFacade schedulerFacade;\n    \n    public ShutdownListenerManager(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        super(regCenter, jobName);\n        this.jobName = jobName;\n        instanceNode = new InstanceNode(jobName);\n        instanceService = new InstanceService(regCenter, jobName);\n        schedulerFacade = new SchedulerFacade(regCenter, jobName);\n    }\n    \n    @Override\n    public void start() {\n        addDataListener(new InstanceShutdownStatusJobListener());\n    }\n    \n    class InstanceShutdownStatusJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (!JobRegistry.getInstance().isShutdown(jobName) && !JobRegistry.getInstance().getJobScheduleController(jobName).isPaused()\n                    && isRemoveInstance(event.getKey(), event.getType()) && !isReconnectedRegistryCenter()) {\n                schedulerFacade.shutdownInstance();\n            }\n        }\n        \n        private boolean isRemoveInstance(final String path, final Type eventType) {\n            return instanceNode.isLocalInstancePath(path) && Type.DELETED == eventType;\n        }\n        \n        private boolean isReconnectedRegistryCenter() {\n            return instanceService.isLocalJobInstanceExisted();\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/listener/AbstractListenerManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.listener;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\n/**\n * Listener manager.\n */\npublic abstract class AbstractListenerManager {\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    protected AbstractListenerManager(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n    }\n    \n    /**\n     * Start listener.\n     */\n    public abstract void start();\n    \n    protected void addDataListener(final DataChangedEventListener listener) {\n        jobNodeStorage.addDataListener(listener);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/listener/ListenerManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.RescheduleListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.ElectionListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.guarantee.GuaranteeListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.ShutdownListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.MonitorExecutionListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.trigger.TriggerListenerManager;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.util.Collection;\n\n/**\n * Listener manager facade.\n */\npublic final class ListenerManager {\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    private final ElectionListenerManager electionListenerManager;\n    \n    private final ShardingListenerManager shardingListenerManager;\n    \n    private final FailoverListenerManager failoverListenerManager;\n    \n    private final MonitorExecutionListenerManager monitorExecutionListenerManager;\n    \n    private final ShutdownListenerManager shutdownListenerManager;\n    \n    private final TriggerListenerManager triggerListenerManager;\n    \n    private final RescheduleListenerManager rescheduleListenerManager;\n    \n    private final GuaranteeListenerManager guaranteeListenerManager;\n    \n    private final RegistryCenterConnectionStateListener regCenterConnectionStateListener;\n    \n    public ListenerManager(final CoordinatorRegistryCenter regCenter, final String jobName, final Collection<ElasticJobListener> elasticJobListeners) {\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        ListenerNotifierManager.getInstance().registerJobNotifyExecutor(jobName);\n        electionListenerManager = new ElectionListenerManager(regCenter, jobName);\n        shardingListenerManager = new ShardingListenerManager(regCenter, jobName);\n        failoverListenerManager = new FailoverListenerManager(regCenter, jobName);\n        monitorExecutionListenerManager = new MonitorExecutionListenerManager(regCenter, jobName);\n        shutdownListenerManager = new ShutdownListenerManager(regCenter, jobName);\n        triggerListenerManager = new TriggerListenerManager(regCenter, jobName);\n        rescheduleListenerManager = new RescheduleListenerManager(regCenter, jobName);\n        guaranteeListenerManager = new GuaranteeListenerManager(regCenter, jobName, elasticJobListeners);\n        regCenterConnectionStateListener = new RegistryCenterConnectionStateListener(regCenter, jobName);\n    }\n    \n    /**\n     * Start all listeners.\n     */\n    public void startAllListeners() {\n        electionListenerManager.start();\n        shardingListenerManager.start();\n        failoverListenerManager.start();\n        monitorExecutionListenerManager.start();\n        shutdownListenerManager.start();\n        triggerListenerManager.start();\n        rescheduleListenerManager.start();\n        guaranteeListenerManager.start();\n        jobNodeStorage.addConnectionStateListener(regCenterConnectionStateListener);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/listener/ListenerNotifierManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.listener;\n\nimport org.apache.curator.utils.ThreadUtils;\n\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadFactory;\n\n/**\n * Manage listener's notify executor,\n * each job has its own listener notify executor.\n */\npublic final class ListenerNotifierManager {\n    \n    private static volatile ListenerNotifierManager instance;\n    \n    private final Map<String, ExecutorService> listenerNotifyExecutors = new ConcurrentHashMap<>();\n    \n    private ListenerNotifierManager() {\n    }\n    \n    /**\n     * Get singleton instance of ListenerNotifierManager.\n     * @return singleton instance of ListenerNotifierManager.\n     */\n    public static ListenerNotifierManager getInstance() {\n        if (null == instance) {\n            synchronized (ListenerNotifierManager.class) {\n                if (null == instance) {\n                    instance = new ListenerNotifierManager();\n                }\n            }\n        }\n        return instance;\n    }\n    \n    /**\n     * Register a listener notify executor for the job specified.\n     * @param jobName The job's name.\n     */\n    public void registerJobNotifyExecutor(final String jobName) {\n        if (!listenerNotifyExecutors.containsKey(jobName)) {\n            synchronized (this) {\n                if (!listenerNotifyExecutors.containsKey(jobName)) {\n                    ThreadFactory threadFactory = ThreadUtils.newGenericThreadFactory(\"ListenerNotify-\" + jobName);\n                    ExecutorService notifyExecutor = Executors.newSingleThreadExecutor(threadFactory);\n                    listenerNotifyExecutors.put(jobName, notifyExecutor);\n                }\n            }\n        }\n    }\n    \n    /**\n     * Get the listener notify executor for the specified job.\n     * @param jobName The job's name.\n     * @return The job listener's notify executor.\n     */\n    public Executor getJobNotifyExecutor(final String jobName) {\n        return listenerNotifyExecutors.get(jobName);\n    }\n    \n    /**\n     * Remove and shutdown the listener notify executor from listenerNotifyExecutors.\n     * @param jobName The job's name.\n     */\n    public void removeJobNotifyExecutor(final String jobName) {\n        Optional.ofNullable(listenerNotifyExecutors.remove(jobName)).ifPresent(ExecutorService::shutdown);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/listener/RegistryCenterConnectionStateListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.listener;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.ConnectionStateChangedEventListener;\n\n/**\n * Registry center connection state listener.\n */\npublic final class RegistryCenterConnectionStateListener implements ConnectionStateChangedEventListener {\n    \n    private final String jobName;\n    \n    private final ServerService serverService;\n    \n    private final InstanceService instanceService;\n    \n    private final ShardingService shardingService;\n    \n    private final ExecutionService executionService;\n    \n    public RegistryCenterConnectionStateListener(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        this.jobName = jobName;\n        serverService = new ServerService(regCenter, jobName);\n        instanceService = new InstanceService(regCenter, jobName);\n        shardingService = new ShardingService(regCenter, jobName);\n        executionService = new ExecutionService(regCenter, jobName);\n    }\n    \n    @Override\n    public void onStateChanged(final CoordinatorRegistryCenter registryCenter, final State newState) {\n        if (JobRegistry.getInstance().isShutdown(jobName)) {\n            return;\n        }\n        JobScheduleController jobScheduleController = JobRegistry.getInstance().getJobScheduleController(jobName);\n        if (State.UNAVAILABLE == newState) {\n            jobScheduleController.pauseJob();\n        } else if (State.RECONNECTED == newState) {\n            serverService.persistOnline(serverService.isEnableServer(JobRegistry.getInstance().getJobInstance(jobName).getServerIp()));\n            instanceService.persistOnline();\n            executionService.clearRunningInfo(shardingService.getLocalShardingItems());\n            jobScheduleController.resumeJob();\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/reconcile/ReconcileService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.reconcile;\n\nimport com.google.common.util.concurrent.AbstractScheduledService;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Reconcile service.\n */\n@Slf4j\npublic final class ReconcileService extends AbstractScheduledService {\n    \n    private long lastReconcileTime;\n    \n    private final ConfigurationService configService;\n    \n    private final ShardingService shardingService;\n    \n    private final JobNodePath jobNodePath;\n    \n    private final CoordinatorRegistryCenter regCenter;\n    \n    public ReconcileService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        this.regCenter = regCenter;\n        lastReconcileTime = System.currentTimeMillis();\n        configService = new ConfigurationService(regCenter, jobName);\n        shardingService = new ShardingService(regCenter, jobName);\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    @Override\n    protected void runOneIteration() {\n        int reconcileIntervalMinutes = configService.load(true).getReconcileIntervalMinutes();\n        if (reconcileIntervalMinutes > 0 && System.currentTimeMillis() - lastReconcileTime >= (long) reconcileIntervalMinutes * 60 * 1000) {\n            lastReconcileTime = System.currentTimeMillis();\n            if (!shardingService.isNeedSharding() && shardingService.hasShardingInfoInOfflineServers() && !(isStaticSharding() && hasShardingInfo())) {\n                log.warn(\"Elastic Job: job status node has inconsistent value,start reconciling...\");\n                shardingService.setReshardingFlag();\n            }\n        }\n    }\n    \n    private boolean isStaticSharding() {\n        return configService.load(true).isStaticSharding();\n    }\n    \n    private boolean hasShardingInfo() {\n        return !regCenter.getChildrenKeys(jobNodePath.getShardingNodePath()).isEmpty();\n    }\n    \n    @Override\n    protected Scheduler scheduler() {\n        return Scheduler.newFixedDelaySchedule(0, 1, TimeUnit.MINUTES);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/JobRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.ListenerNotifierManager;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Job registry.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class JobRegistry {\n    \n    private static volatile JobRegistry instance;\n    \n    private final Map<String, JobScheduleController> schedulerMap = new ConcurrentHashMap<>();\n    \n    private final Map<String, CoordinatorRegistryCenter> regCenterMap = new ConcurrentHashMap<>();\n    \n    private final Map<String, JobInstance> jobInstanceMap = new ConcurrentHashMap<>();\n    \n    private final Map<String, Boolean> jobRunningMap = new ConcurrentHashMap<>();\n    \n    private final Map<String, Integer> currentShardingTotalCountMap = new ConcurrentHashMap<>();\n    \n    /**\n     * Get instance of job registry.\n     * \n     * @return instance of job registry\n     */\n    public static JobRegistry getInstance() {\n        if (null == instance) {\n            synchronized (JobRegistry.class) {\n                if (null == instance) {\n                    instance = new JobRegistry();\n                }\n            }\n        }\n        return instance;\n    }\n    \n    /**\n     * Register registry center.\n     *\n     * @param jobName job name\n     * @param regCenter registry center\n     */\n    public void registerRegistryCenter(final String jobName, final CoordinatorRegistryCenter regCenter) {\n        regCenterMap.put(jobName, regCenter);\n        regCenter.addCacheData(\"/\" + jobName);\n    }\n    \n    /**\n     * Register job.\n     * \n     * @param jobName job name\n     * @param jobScheduleController job schedule controller\n     */\n    public void registerJob(final String jobName, final JobScheduleController jobScheduleController) {\n        schedulerMap.put(jobName, jobScheduleController);\n    }\n    \n    /**\n     * Get job schedule controller.\n     * \n     * @param jobName job name\n     * @return job schedule controller\n     */\n    public JobScheduleController getJobScheduleController(final String jobName) {\n        return schedulerMap.get(jobName);\n    }\n    \n    /**\n     * Get registry center.\n     *\n     * @param jobName job name\n     * @return registry center\n     */\n    public CoordinatorRegistryCenter getRegCenter(final String jobName) {\n        return regCenterMap.get(jobName);\n    }\n    \n    /**\n     * Add job instance.\n     *\n     * @param jobName job name\n     * @param jobInstance job instance\n     */\n    public void addJobInstance(final String jobName, final JobInstance jobInstance) {\n        jobInstanceMap.put(jobName, jobInstance);\n    }\n    \n    /**\n     * Get job instance.\n     *\n     * @param jobName job name\n     * @return job instance\n     */\n    public JobInstance getJobInstance(final String jobName) {\n        return jobInstanceMap.get(jobName);\n    }\n    \n    /**\n     * Judge job is running or not.\n     * \n     * @param jobName job name\n     * @return job is running or not\n     */\n    public boolean isJobRunning(final String jobName) {\n        return jobRunningMap.getOrDefault(jobName, false);\n    }\n    \n    /**\n     * Set job running status.\n     * \n     * @param jobName job name\n     * @param isRunning job running status\n     */\n    public void setJobRunning(final String jobName, final boolean isRunning) {\n        jobRunningMap.put(jobName, isRunning);\n    }\n    \n    /**\n     * Get sharding total count which running on current job server.\n     *\n     * @param jobName job name\n     * @return sharding total count which running on current job server\n     */\n    public int getCurrentShardingTotalCount(final String jobName) {\n        return currentShardingTotalCountMap.getOrDefault(jobName, 0);\n    }\n    \n    /**\n     * Set sharding total count which running on current job server.\n     *\n     * @param jobName job name\n     * @param currentShardingTotalCount sharding total count which running on current job server\n     */\n    public void setCurrentShardingTotalCount(final String jobName, final int currentShardingTotalCount) {\n        currentShardingTotalCountMap.put(jobName, currentShardingTotalCount);\n    }\n    \n    /**\n     * Shutdown job schedule.\n     * \n     * @param jobName job name\n     */\n    public void shutdown(final String jobName) {\n        Optional.ofNullable(schedulerMap.remove(jobName)).ifPresent(JobScheduleController::shutdown);\n        Optional.ofNullable(regCenterMap.remove(jobName)).ifPresent(regCenter -> regCenter.evictCacheData(\"/\" + jobName));\n        ListenerNotifierManager.getInstance().removeJobNotifyExecutor(jobName);\n        jobInstanceMap.remove(jobName);\n        jobRunningMap.remove(jobName);\n        currentShardingTotalCountMap.remove(jobName);\n    }\n    \n    /**\n     * Judge job is shutdown or not.\n     * \n     * @param jobName job name\n     * @return job is shutdown or not\n     */\n    public boolean isShutdown(final String jobName) {\n        return !schedulerMap.containsKey(jobName) || !jobInstanceMap.containsKey(jobName);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/JobScheduleController.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.quartz.CronScheduleBuilder;\nimport org.quartz.CronTrigger;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.SimpleScheduleBuilder;\nimport org.quartz.SimpleTrigger;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerBuilder;\nimport org.quartz.TriggerKey;\n\nimport java.util.TimeZone;\n\n/**\n * Job schedule controller.\n */\n@RequiredArgsConstructor\npublic final class JobScheduleController {\n    \n    private final Scheduler scheduler;\n    \n    private final JobDetail jobDetail;\n    \n    private final String triggerIdentity;\n    \n    /**\n     * Schedule job.\n     * \n     * @param cron CRON expression\n     * @param timeZone the time zone\n     */\n    public void scheduleJob(final String cron, final String timeZone) {\n        try {\n            if (!scheduler.checkExists(jobDetail.getKey())) {\n                scheduler.scheduleJob(jobDetail, createCronTrigger(cron, timeZone));\n            }\n            scheduler.start();\n        } catch (final SchedulerException ex) {\n            throw new JobSystemException(ex);\n        }\n    }\n    \n    /**\n     * Reschedule job.\n     * \n     * @param cron CRON expression\n     * @param timeZone the time zone\n     */\n    public synchronized void rescheduleJob(final String cron, final String timeZone) {\n        try {\n            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(TriggerKey.triggerKey(triggerIdentity));\n            if (!scheduler.isShutdown() && null != trigger && !cron.equals(trigger.getCronExpression())) {\n                scheduler.rescheduleJob(TriggerKey.triggerKey(triggerIdentity), createCronTrigger(cron, timeZone));\n            }\n        } catch (final SchedulerException ex) {\n            throw new JobSystemException(ex);\n        }\n    }\n    \n    /**\n     * Reschedule OneOff job.\n     */\n    public synchronized void rescheduleJob() {\n        try {\n            SimpleTrigger trigger = (SimpleTrigger) scheduler.getTrigger(TriggerKey.triggerKey(triggerIdentity));\n            if (!scheduler.isShutdown() && null != trigger) {\n                scheduler.rescheduleJob(TriggerKey.triggerKey(triggerIdentity), createOneOffTrigger());\n            }\n        } catch (final SchedulerException ex) {\n            throw new JobSystemException(ex);\n        }\n    }\n    \n    private Trigger createCronTrigger(final String cron, final String timeZoneString) {\n        return TriggerBuilder.newTrigger().withIdentity(triggerIdentity).withSchedule(\n                CronScheduleBuilder.cronSchedule(cron).inTimeZone(parseTimeZoneString(timeZoneString)).withMisfireHandlingInstructionDoNothing()).build();\n    }\n    \n    /**\n     * Get the TimeZone for the time zone specification.\n     *\n     * @param timeZoneString must start with \"GMT\", such as \"GMT+8:00\"\n     * @return the specified TimeZone, or the GMT zone if the `timeZoneString` cannot be understood.\n     */\n    private TimeZone parseTimeZoneString(final String timeZoneString) {\n        if (Strings.isNullOrEmpty(timeZoneString)) {\n            return TimeZone.getDefault();\n        }\n        Preconditions.checkArgument(timeZoneString.startsWith(\"GMT\"), \"Invalid time zone specification '%s'.\", timeZoneString);\n        return TimeZone.getTimeZone(timeZoneString);\n    }\n    \n    /**\n     * Judge job is pause or not.\n     * \n     * @return job is pause or not\n     */\n    public synchronized boolean isPaused() {\n        try {\n            return !scheduler.isShutdown() && Trigger.TriggerState.PAUSED == scheduler.getTriggerState(new TriggerKey(triggerIdentity));\n        } catch (final SchedulerException ex) {\n            throw new JobSystemException(ex);\n        }\n    }\n    \n    /**\n     * Pause job.\n     */\n    public synchronized void pauseJob() {\n        try {\n            if (!scheduler.isShutdown()) {\n                scheduler.pauseAll();\n            }\n        } catch (final SchedulerException ex) {\n            throw new JobSystemException(ex);\n        }\n    }\n    \n    /**\n     * Resume job.\n     */\n    public synchronized void resumeJob() {\n        try {\n            if (!scheduler.isShutdown()) {\n                scheduler.resumeAll();\n            }\n        } catch (final SchedulerException ex) {\n            throw new JobSystemException(ex);\n        }\n    }\n    \n    /**\n     * Trigger job.\n     */\n    public synchronized void triggerJob() {\n        try {\n            if (scheduler.isShutdown()) {\n                return;\n            }\n            if (!scheduler.checkExists(jobDetail.getKey())) {\n                scheduler.scheduleJob(jobDetail, createOneOffTrigger());\n            } else {\n                scheduler.triggerJob(jobDetail.getKey());\n            }\n            if (!scheduler.isStarted()) {\n                scheduler.start();\n            }\n        } catch (final SchedulerException ex) {\n            throw new JobSystemException(ex);\n        }\n    }\n    \n    private Trigger createOneOffTrigger() {\n        return TriggerBuilder.newTrigger().withIdentity(triggerIdentity).withSchedule(SimpleScheduleBuilder.simpleSchedule()).build();\n    }\n    \n    /**\n     * Shutdown scheduler.\n     */\n    public synchronized void shutdown() {\n        shutdown(false);\n    }\n    \n    /**\n     * Shutdown scheduler graceful.\n     * @param isCleanShutdown if wait jobs complete\n     */\n    public synchronized void shutdown(final boolean isCleanShutdown) {\n        try {\n            if (!scheduler.isShutdown()) {\n                scheduler.shutdown(isCleanShutdown);\n            }\n        } catch (final SchedulerException ex) {\n            throw new JobSystemException(ex);\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/JobScheduler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.facade.SingleShardingJobFacade;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandlerPropertiesValidator;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.ElasticJobExecutor;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.facade.ShardingJobFacade;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.facade.JobFacade;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.AbstractDistributeOnceElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.guarantee.GuaranteeService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.setup.JobClassNameProviderFactory;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.setup.SetUpFacade;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.quartz.JobBuilder;\nimport org.quartz.JobDetail;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.impl.StdSchedulerFactory;\nimport org.quartz.simpl.SimpleThreadPool;\n\nimport java.util.Collection;\nimport java.util.Optional;\nimport java.util.Properties;\nimport java.util.stream.Collectors;\n\n/**\n * Job scheduler.\n */\npublic final class JobScheduler {\n    \n    private static final String JOB_EXECUTOR_DATA_MAP_KEY = \"jobExecutor\";\n    \n    @Getter\n    private final CoordinatorRegistryCenter regCenter;\n    \n    @Getter\n    private final JobConfiguration jobConfig;\n    \n    private final SetUpFacade setUpFacade;\n    \n    private final SchedulerFacade schedulerFacade;\n    \n    private final JobFacade jobFacade;\n    \n    private final ElasticJobExecutor jobExecutor;\n    \n    @Getter\n    private final JobScheduleController jobScheduleController;\n    \n    public JobScheduler(final CoordinatorRegistryCenter regCenter, final ElasticJob elasticJob, final JobConfiguration jobConfig) {\n        Preconditions.checkArgument(null != elasticJob, \"Elastic job cannot be null.\");\n        this.regCenter = regCenter;\n        String jobClassName = JobClassNameProviderFactory.getProvider().getJobClassName(elasticJob);\n        this.jobConfig = setUpJobConfiguration(regCenter, jobClassName, jobConfig);\n        Collection<ElasticJobListener> jobListeners = getElasticJobListeners(this.jobConfig);\n        setUpFacade = new SetUpFacade(regCenter, this.jobConfig.getJobName(), jobListeners);\n        schedulerFacade = new SchedulerFacade(regCenter, this.jobConfig.getJobName());\n        \n        if (1 == this.jobConfig.getShardingTotalCount()\n                && \"SINGLE_SHARDING_BALANCE\".equals(this.jobConfig.getJobShardingStrategyType())) {\n            jobFacade = new SingleShardingJobFacade(regCenter, this.jobConfig.getJobName(), jobListeners, findTracingConfiguration().orElse(null));\n        } else {\n            jobFacade = new ShardingJobFacade(regCenter, this.jobConfig.getJobName(), jobListeners, findTracingConfiguration().orElse(null));\n        }\n        \n        validateJobProperties();\n        jobExecutor = new ElasticJobExecutor(elasticJob, this.jobConfig, jobFacade);\n        setGuaranteeServiceForElasticJobListeners(regCenter, jobListeners);\n        jobScheduleController = createJobScheduleController();\n    }\n    \n    public JobScheduler(final CoordinatorRegistryCenter regCenter, final String elasticJobType, final JobConfiguration jobConfig) {\n        Preconditions.checkArgument(!Strings.isNullOrEmpty(elasticJobType), \"Elastic job type cannot be null or empty.\");\n        this.regCenter = regCenter;\n        this.jobConfig = setUpJobConfiguration(regCenter, elasticJobType, jobConfig);\n        Collection<ElasticJobListener> jobListeners = getElasticJobListeners(this.jobConfig);\n        setUpFacade = new SetUpFacade(regCenter, this.jobConfig.getJobName(), jobListeners);\n        schedulerFacade = new SchedulerFacade(regCenter, this.jobConfig.getJobName());\n        \n        if (1 == this.jobConfig.getShardingTotalCount()\n                && \"SINGLE_SHARDING_BALANCE\".equals(this.jobConfig.getJobShardingStrategyType())) {\n            jobFacade = new SingleShardingJobFacade(regCenter, this.jobConfig.getJobName(), jobListeners, findTracingConfiguration().orElse(null));\n        } else {\n            jobFacade = new ShardingJobFacade(regCenter, this.jobConfig.getJobName(), jobListeners, findTracingConfiguration().orElse(null));\n        }\n        \n        validateJobProperties();\n        jobExecutor = new ElasticJobExecutor(elasticJobType, this.jobConfig, jobFacade);\n        setGuaranteeServiceForElasticJobListeners(regCenter, jobListeners);\n        jobScheduleController = createJobScheduleController();\n    }\n    \n    private JobConfiguration setUpJobConfiguration(final CoordinatorRegistryCenter regCenter, final String jobClassName, final JobConfiguration jobConfig) {\n        ConfigurationService configService = new ConfigurationService(regCenter, jobConfig.getJobName());\n        return configService.setUpJobConfiguration(jobClassName, jobConfig);\n    }\n    \n    private Collection<ElasticJobListener> getElasticJobListeners(final JobConfiguration jobConfig) {\n        return jobConfig.getJobListenerTypes().stream().map(each -> TypedSPILoader.getService(ElasticJobListener.class, each)).collect(Collectors.toList());\n    }\n    \n    private Optional<TracingConfiguration<?>> findTracingConfiguration() {\n        return jobConfig.getExtraConfigurations().stream().filter(each -> each instanceof TracingConfiguration).findFirst().map(extraConfig -> (TracingConfiguration<?>) extraConfig);\n    }\n    \n    private void validateJobProperties() {\n        validateJobErrorHandlerProperties();\n    }\n    \n    private void validateJobErrorHandlerProperties() {\n        if (null != jobConfig.getJobErrorHandlerType()) {\n            TypedSPILoader.findService(JobErrorHandlerPropertiesValidator.class, jobConfig.getJobErrorHandlerType(), jobConfig.getProps())\n                    .ifPresent(validator -> validator.validate(jobConfig.getProps()));\n        }\n    }\n    \n    private void setGuaranteeServiceForElasticJobListeners(final CoordinatorRegistryCenter regCenter, final Collection<ElasticJobListener> elasticJobListeners) {\n        GuaranteeService guaranteeService = new GuaranteeService(regCenter, jobConfig.getJobName());\n        for (ElasticJobListener each : elasticJobListeners) {\n            if (each instanceof AbstractDistributeOnceElasticJobListener) {\n                ((AbstractDistributeOnceElasticJobListener) each).setGuaranteeService(guaranteeService);\n            }\n        }\n    }\n    \n    private JobScheduleController createJobScheduleController() {\n        JobScheduleController result = new JobScheduleController(createScheduler(), createJobDetail(), getJobConfig().getJobName());\n        JobRegistry.getInstance().registerJob(getJobConfig().getJobName(), result);\n        registerStartUpInfo();\n        return result;\n    }\n    \n    private Scheduler createScheduler() {\n        Scheduler result;\n        try {\n            StdSchedulerFactory factory = new StdSchedulerFactory();\n            factory.initialize(getQuartzProps());\n            result = factory.getScheduler();\n            result.getListenerManager().addTriggerListener(schedulerFacade.newJobTriggerListener());\n        } catch (final SchedulerException ex) {\n            throw new JobSystemException(ex);\n        }\n        return result;\n    }\n    \n    private Properties getQuartzProps() {\n        Properties result = new Properties();\n        result.put(\"org.quartz.threadPool.class\", SimpleThreadPool.class.getName());\n        result.put(\"org.quartz.threadPool.threadCount\", \"1\");\n        result.put(\"org.quartz.scheduler.instanceName\", getJobConfig().getJobName());\n        result.put(\"org.quartz.jobStore.misfireThreshold\", \"1\");\n        result.put(\"org.quartz.plugin.shutdownhook.class\", JobShutdownHookPlugin.class.getName());\n        result.put(\"org.quartz.plugin.shutdownhook.cleanShutdown\", Boolean.TRUE.toString());\n        result.put(\"org.quartz.scheduler.interruptJobsOnShutdown\", Boolean.TRUE.toString());\n        return result;\n    }\n    \n    private JobDetail createJobDetail() {\n        JobDetail result = JobBuilder.newJob(LiteJob.class).withIdentity(getJobConfig().getJobName()).build();\n        result.getJobDataMap().put(JOB_EXECUTOR_DATA_MAP_KEY, jobExecutor);\n        return result;\n    }\n    \n    private void registerStartUpInfo() {\n        JobRegistry.getInstance().registerRegistryCenter(jobConfig.getJobName(), regCenter);\n        JobRegistry.getInstance().addJobInstance(jobConfig.getJobName(), new JobInstance());\n        JobRegistry.getInstance().setCurrentShardingTotalCount(jobConfig.getJobName(), jobConfig.getShardingTotalCount());\n        setUpFacade.registerStartUpInfo(!jobConfig.isDisabled());\n    }\n    \n    /**\n     * Shutdown job.\n     */\n    public void shutdown() {\n        setUpFacade.tearDown();\n        schedulerFacade.shutdownInstance();\n        jobScheduleController.shutdown(false);\n        jobExecutor.shutdown();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/JobShutdownHookPlugin.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.spi.ClassLoadHelper;\nimport org.quartz.spi.SchedulerPlugin;\n\n/**\n * Job shutdown hook plugin.\n */\n@Slf4j\n@Getter\npublic final class JobShutdownHookPlugin implements SchedulerPlugin {\n    \n    private String jobName;\n    \n    @Setter\n    private boolean cleanShutdown = true;\n    \n    @Override\n    public void initialize(final String name, final Scheduler scheduler, final ClassLoadHelper classLoadHelper) throws SchedulerException {\n        jobName = scheduler.getSchedulerName();\n        registerShutdownHook();\n    }\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    @Override\n    public void start() {\n        \n    }\n    \n    @Override\n    public void shutdown() {\n        CoordinatorRegistryCenter regCenter = JobRegistry.getInstance().getRegCenter(jobName);\n        if (null == regCenter) {\n            return;\n        }\n        LeaderService leaderService = new LeaderService(regCenter, jobName);\n        if (leaderService.isLeader()) {\n            leaderService.removeLeader();\n        }\n        new InstanceService(regCenter, jobName).removeInstance();\n    }\n    \n    private void registerShutdownHook() {\n        log.info(\"Registering Quartz shutdown hook. {}\", jobName);\n        Thread t = new Thread(\"Quartz Shutdown-Hook \" + jobName) {\n            \n            @Override\n            public void run() {\n                log.info(\"Shutting down Quartz... {}\", jobName);\n                JobScheduleController scheduleController = JobRegistry.getInstance().getJobScheduleController(jobName);\n                if (null != scheduleController) {\n                    scheduleController.shutdown(isCleanShutdown());\n                }\n            }\n        };\n        Runtime.getRuntime().addShutdownHook(t);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/JobTriggerListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.quartz.Trigger;\nimport org.quartz.listeners.TriggerListenerSupport;\n\n/**\n * Job trigger listener.\n */\n@RequiredArgsConstructor\npublic final class JobTriggerListener extends TriggerListenerSupport {\n    \n    private final ExecutionService executionService;\n    \n    private final ShardingService shardingService;\n    \n    @Override\n    public String getName() {\n        return \"JobTriggerListener\";\n    }\n    \n    @Override\n    public void triggerMisfired(final Trigger trigger) {\n        if (null != trigger.getPreviousFireTime()) {\n            executionService.setMisfire(shardingService.getLocalShardingItems());\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/LiteJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.ElasticJobExecutor;\nimport org.quartz.InterruptableJob;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.UnableToInterruptJobException;\n\nimport java.util.Objects;\n\n/**\n * Lite job.\n */\n@Setter\npublic final class LiteJob implements InterruptableJob {\n    \n    private ElasticJobExecutor jobExecutor;\n    \n    private volatile Thread currentThread;\n    \n    @Override\n    public void execute(final JobExecutionContext context) {\n        try {\n            currentThread = Thread.currentThread();\n            jobExecutor.execute();\n        } finally {\n            currentThread = null;\n        }\n    }\n    \n    @Override\n    public void interrupt() throws UnableToInterruptJobException {\n        if (Objects.nonNull(currentThread)) {\n            currentThread.interrupt();\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/SchedulerFacade.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\n/**\n * Scheduler facade.\n */\npublic final class SchedulerFacade {\n    \n    private final String jobName;\n    \n    private final LeaderService leaderService;\n    \n    private final ShardingService shardingService;\n    \n    private final ExecutionService executionService;\n    \n    public SchedulerFacade(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        this.jobName = jobName;\n        leaderService = new LeaderService(regCenter, jobName);\n        shardingService = new ShardingService(regCenter, jobName);\n        executionService = new ExecutionService(regCenter, jobName);\n    }\n    \n    /**\n     * Create job trigger listener.\n     *\n     * @return job trigger listener\n     */\n    public JobTriggerListener newJobTriggerListener() {\n        return new JobTriggerListener(executionService, shardingService);\n    }\n    \n    /**\n     * Shutdown instance.\n     */\n    public void shutdownInstance() {\n        if (leaderService.isLeader()) {\n            leaderService.removeLeader();\n        }\n        JobRegistry.getInstance().shutdown(jobName);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/server/ServerNode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.server;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.env.IpUtils;\n\nimport java.util.Objects;\nimport java.util.regex.Pattern;\n\n/**\n * Server node.\n */\npublic final class ServerNode {\n    \n    public static final String ROOT = \"servers\";\n    \n    private static final String SERVERS = ROOT + \"/%s\";\n    \n    private final String jobName;\n    \n    private final JobNodePath jobNodePath;\n    \n    public ServerNode(final String jobName) {\n        this.jobName = jobName;\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    /**\n     * Judge is server path or not.\n     *\n     * @param path path to be judged\n     * @return is server path or not\n     */\n    public boolean isServerPath(final String path) {\n        return Pattern.compile(jobNodePath.getFullPath(ServerNode.ROOT) + \"/\" + IpUtils.IP_REGEX).matcher(path).matches();\n    }\n    \n    /**\n     * Judge is server path for localhost or not.\n     *\n     * @param path path to be judged\n     * @return is server path for localhost or not\n     */\n    public boolean isLocalServerPath(final String path) {\n        JobInstance jobInstance = JobRegistry.getInstance().getJobInstance(jobName);\n        if (Objects.isNull(jobInstance)) {\n            return false;\n        }\n        return path.equals(jobNodePath.getFullPath(String.format(SERVERS, jobInstance.getServerIp())));\n    }\n    \n    String getServerNode(final String ip) {\n        return String.format(SERVERS, ip);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/server/ServerService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.server;\n\nimport com.google.common.base.Strings;\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.util.BlockUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.stream.Collectors;\n\n/**\n * Server service.\n */\npublic final class ServerService {\n    \n    private final String jobName;\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    private final ServerNode serverNode;\n    \n    public ServerService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        this.jobName = jobName;\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        serverNode = new ServerNode(jobName);\n    }\n    \n    /**\n     * Persist online status of job server.\n     *\n     * @param enabled enable server or not\n     */\n    public void persistOnline(final boolean enabled) {\n        if (!JobRegistry.getInstance().isShutdown(jobName)) {\n            jobNodeStorage.fillJobNode(serverNode.getServerNode(JobRegistry.getInstance().getJobInstance(jobName).getServerIp()), enabled ? ServerStatus.ENABLED.name() : ServerStatus.DISABLED.name());\n        }\n    }\n    \n    /**\n     * Judge has available servers or not.\n     *\n     * @return has available servers or not\n     */\n    public boolean hasAvailableServers() {\n        List<String> servers = jobNodeStorage.getJobNodeChildrenKeys(ServerNode.ROOT);\n        for (String each : servers) {\n            if (isAvailableServer(each)) {\n                return true;\n            }\n        }\n        return false;\n    }\n    \n    /**\n     * Judge is available server or not.\n     *\n     * @param ip job server IP address\n     * @return is available server or not\n     */\n    public boolean isAvailableServer(final String ip) {\n        return isEnableServer(ip) && hasOnlineInstances(ip);\n    }\n    \n    private boolean hasOnlineInstances(final String ip) {\n        for (String each : jobNodeStorage.getJobNodeChildrenKeys(InstanceNode.ROOT)) {\n            if (each.startsWith(ip)) {\n                return true;\n            }\n        }\n        return false;\n    }\n    \n    /**\n     * Judge is server enabled or not.\n     *\n     * @param ip job server IP address\n     * @return is server enabled or not\n     */\n    public boolean isEnableServer(final String ip) {\n        String serverStatus = jobNodeStorage.getJobNodeData(serverNode.getServerNode(ip));\n        for (int i = 0; Strings.isNullOrEmpty(serverStatus) && i < 10; i++) {\n            BlockUtils.waitingShortTime();\n            serverStatus = jobNodeStorage.getJobNodeData(serverNode.getServerNode(ip));\n        }\n        return ServerStatus.ENABLED.name().equals(serverStatus);\n    }\n    \n    /**\n     *  Remove unused server IP.\n     *\n     * @return num of server IP to be removed\n     */\n    public int removeOfflineServers() {\n        AtomicInteger affectNums = new AtomicInteger();\n        Collection<String> instances = jobNodeStorage.getJobNodeChildrenKeys(InstanceNode.ROOT);\n        if (instances == null || instances.isEmpty()) {\n            return affectNums.get();\n        }\n        Collection<String> instanceIps = instances.stream().map(instance -> instance.split(\"@-@\")[0]).collect(Collectors.toSet());\n        if (instanceIps.isEmpty()) {\n            return affectNums.get();\n        }\n        List<String> serverIps = jobNodeStorage.getJobNodeChildrenKeys(ServerNode.ROOT);\n        if (serverIps == null || serverIps.isEmpty()) {\n            return affectNums.get();\n        }\n        \n        serverIps.forEach(serverIp -> {\n            if (instanceIps.contains(serverIp)) {\n                return;\n            }\n            String status = jobNodeStorage.getJobNodeData(serverNode.getServerNode(serverIp));\n            if (StringUtils.isBlank(status)) {\n                return;\n            }\n            jobNodeStorage.removeJobNodeIfExisted(serverNode.getServerNode(serverIp));\n            affectNums.getAndIncrement();\n        });\n        return affectNums.get();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/server/ServerStatus.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.server;\n\n/**\n * Server status.\n */\npublic enum ServerStatus {\n    \n    ENABLED, DISABLED\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/setup/DefaultJobClassNameProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.setup;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\n\n/**\n * Simple job class name provider.\n */\npublic final class DefaultJobClassNameProvider implements JobClassNameProvider {\n    \n    private static final String LAMBDA_CHARACTERISTICS = \"$$Lambda\";\n    \n    @Override\n    public String getJobClassName(final ElasticJob elasticJob) {\n        Class<? extends ElasticJob> elasticJobClass = elasticJob.getClass();\n        String elasticJobClassName = elasticJobClass.getName();\n        return isLambdaClass(elasticJobClass) ? trimLambdaClassSuffix(elasticJobClassName) : elasticJobClassName;\n    }\n    \n    private boolean isLambdaClass(final Class<? extends ElasticJob> elasticJobClass) {\n        return elasticJobClass.isSynthetic() && elasticJobClass.getSimpleName().contains(LAMBDA_CHARACTERISTICS);\n    }\n    \n    private String trimLambdaClassSuffix(final String className) {\n        return className.substring(0, className.lastIndexOf(LAMBDA_CHARACTERISTICS) + LAMBDA_CHARACTERISTICS.length());\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/setup/JobClassNameProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.setup;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\n\n/**\n * Job class name provider.\n */\n@SingletonSPI\npublic interface JobClassNameProvider {\n    \n    /**\n     * Get job class name.\n     *\n     * @param elasticJob job instance\n     * @return job class name\n     */\n    String getJobClassName(ElasticJob elasticJob);\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/setup/JobClassNameProviderFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.setup;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;\n\nimport java.util.Collection;\n\n/**\n * Job class name provider factory.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class JobClassNameProviderFactory {\n    \n    private static final JobClassNameProvider DEFAULT_PROVIDER = new DefaultJobClassNameProvider();\n    \n    /**\n     * Get the first job class name provider.\n     *\n     * @return job class name provider\n     */\n    public static JobClassNameProvider getProvider() {\n        Collection<JobClassNameProvider> jobClassNameProviders = ShardingSphereServiceLoader.getServiceInstances(JobClassNameProvider.class);\n        return jobClassNameProviders.isEmpty() ? DEFAULT_PROVIDER : jobClassNameProviders.iterator().next();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/setup/SetUpFacade.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.setup;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.ListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.reconcile.ReconcileService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.util.Collection;\n\n/**\n * Set up facade.\n */\npublic final class SetUpFacade {\n    \n    private final LeaderService leaderService;\n    \n    private final ServerService serverService;\n    \n    private final InstanceService instanceService;\n    \n    private final ReconcileService reconcileService;\n    \n    private final ListenerManager listenerManager;\n    \n    /**\n     * JobName.\n     */\n    private final String jobName;\n    \n    /**\n     * Registry center.\n     */\n    private final CoordinatorRegistryCenter regCenter;\n    \n    public SetUpFacade(final CoordinatorRegistryCenter regCenter, final String jobName, final Collection<ElasticJobListener> elasticJobListeners) {\n        leaderService = new LeaderService(regCenter, jobName);\n        serverService = new ServerService(regCenter, jobName);\n        instanceService = new InstanceService(regCenter, jobName);\n        reconcileService = new ReconcileService(regCenter, jobName);\n        listenerManager = new ListenerManager(regCenter, jobName, elasticJobListeners);\n        this.jobName = jobName;\n        this.regCenter = regCenter;\n    }\n    \n    /**\n     * Register start up info.\n     * \n     * @param enabled enable job on startup\n     */\n    public void registerStartUpInfo(final boolean enabled) {\n        listenerManager.startAllListeners();\n        leaderService.electLeader();\n        serverService.persistOnline(enabled);\n        instanceService.persistOnline();\n        if (!reconcileService.isRunning()) {\n            reconcileService.startAsync();\n        }\n        serverService.removeOfflineServers();\n    }\n    \n    /**\n     * Tear down.\n     */\n    public void tearDown() {\n        regCenter.removeConnStateListener(\"/\" + this.jobName);\n        regCenter.removeDataListeners(\"/\" + this.jobName);\n        if (reconcileService.isRunning()) {\n            reconcileService.stopAsync();\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ExecutionContextService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\n/**\n * Execution context service.\n */\npublic final class ExecutionContextService {\n    \n    private final String jobName;\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    private final ConfigurationService configService;\n    \n    public ExecutionContextService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        this.jobName = jobName;\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        configService = new ConfigurationService(regCenter, jobName);\n    }\n    \n    /**\n     * Get job sharding context.\n     * \n     * @param shardingItems sharding items\n     * @return job sharding context\n     */\n    public ShardingContexts getJobShardingContext(final List<Integer> shardingItems) {\n        JobConfiguration jobConfig = configService.load(false);\n        removeRunningIfMonitorExecution(jobConfig.isMonitorExecution(), shardingItems);\n        if (shardingItems.isEmpty()) {\n            return new ShardingContexts(buildTaskId(jobConfig, shardingItems), jobConfig.getJobName(), jobConfig.getShardingTotalCount(),\n                    jobConfig.getJobParameter(), Collections.emptyMap());\n        }\n        Map<Integer, String> shardingItemParameterMap = new ShardingItemParameters(jobConfig.getShardingItemParameters()).getMap();\n        return new ShardingContexts(buildTaskId(jobConfig, shardingItems), jobConfig.getJobName(), jobConfig.getShardingTotalCount(),\n                jobConfig.getJobParameter(), getAssignedShardingItemParameterMap(shardingItems, shardingItemParameterMap));\n    }\n    \n    private String buildTaskId(final JobConfiguration jobConfig, final List<Integer> shardingItems) {\n        JobInstance jobInstance = JobRegistry.getInstance().getJobInstance(jobName);\n        String shardingItemsString = shardingItems.stream().map(Object::toString).collect(Collectors.joining(\",\"));\n        String jobInstanceId = null == jobInstance || null == jobInstance.getJobInstanceId() ? \"127.0.0.1@-@1\" : jobInstance.getJobInstanceId();\n        return String.join(\"@-@\", jobConfig.getJobName(), shardingItemsString, \"READY\", jobInstanceId);\n    }\n    \n    private void removeRunningIfMonitorExecution(final boolean monitorExecution, final List<Integer> shardingItems) {\n        if (!monitorExecution) {\n            return;\n        }\n        List<Integer> runningShardingItems = new ArrayList<>(shardingItems.size());\n        for (int each : shardingItems) {\n            if (isRunning(each)) {\n                runningShardingItems.add(each);\n            }\n        }\n        shardingItems.removeAll(runningShardingItems);\n    }\n    \n    private boolean isRunning(final int shardingItem) {\n        return jobNodeStorage.isJobNodeExisted(ShardingNode.getRunningNode(shardingItem));\n    }\n    \n    private Map<Integer, String> getAssignedShardingItemParameterMap(final List<Integer> shardingItems, final Map<Integer, String> shardingItemParameterMap) {\n        Map<Integer, String> result = new HashMap<>(shardingItems.size(), 1);\n        for (int each : shardingItems) {\n            result.put(each, shardingItemParameterMap.get(each));\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ExecutionService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport com.google.common.base.Strings;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Execution service.\n */\npublic final class ExecutionService {\n    \n    private final String jobName;\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    private final ConfigurationService configService;\n    \n    public ExecutionService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        this.jobName = jobName;\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        configService = new ConfigurationService(regCenter, jobName);\n    }\n    \n    /**\n     * Register job begin.\n     * \n     * @param shardingContexts sharding contexts\n     */\n    public void registerJobBegin(final ShardingContexts shardingContexts) {\n        JobRegistry.getInstance().setJobRunning(jobName, true);\n        JobConfiguration jobConfig = configService.load(true);\n        if (!jobConfig.isMonitorExecution()) {\n            return;\n        }\n        String jobInstanceId = JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId();\n        for (int each : shardingContexts.getShardingItemParameters().keySet()) {\n            if (jobConfig.isFailover()) {\n                jobNodeStorage.fillJobNode(ShardingNode.getRunningNode(each), jobInstanceId);\n            } else {\n                jobNodeStorage.fillEphemeralJobNode(ShardingNode.getRunningNode(each), jobInstanceId);\n            }\n        }\n    }\n    \n    /**\n     * Register job completed.\n     * \n     * @param shardingContexts sharding contexts\n     */\n    public void registerJobCompleted(final ShardingContexts shardingContexts) {\n        JobRegistry.getInstance().setJobRunning(jobName, false);\n        if (!configService.load(true).isMonitorExecution()) {\n            return;\n        }\n        for (int each : shardingContexts.getShardingItemParameters().keySet()) {\n            jobNodeStorage.removeJobNodeIfExisted(ShardingNode.getRunningNode(each));\n        }\n    }\n    \n    /**\n     * Clear all running info.\n     */\n    public void clearAllRunningInfo() {\n        clearRunningInfo(getAllItems());\n    }\n    \n    /**\n     * Clear running info.\n     * \n     * @param items sharding items which need to be cleared\n     */\n    public void clearRunningInfo(final List<Integer> items) {\n        for (int each : items) {\n            jobNodeStorage.removeJobNodeIfExisted(ShardingNode.getRunningNode(each));\n        }\n    }\n    \n    /**\n     * Judge has running items or not.\n     *\n     * @param items sharding items need to be judged\n     * @return has running items or not\n     */\n    public boolean hasRunningItems(final Collection<Integer> items) {\n        JobConfiguration jobConfig = configService.load(true);\n        if (!jobConfig.isMonitorExecution()) {\n            return false;\n        }\n        for (int each : items) {\n            if (jobNodeStorage.isJobNodeExisted(ShardingNode.getRunningNode(each))) {\n                return true;\n            }\n        }\n        return false;\n    }\n    \n    /**\n     * Judge has running items or not.\n     *\n     * @return has running items or not\n     */\n    public boolean hasRunningItems() {\n        return hasRunningItems(getAllItems());\n    }\n    \n    private List<Integer> getAllItems() {\n        int shardingTotalCount = configService.load(true).getShardingTotalCount();\n        List<Integer> result = new ArrayList<>(shardingTotalCount);\n        for (int i = 0; i < shardingTotalCount; i++) {\n            result.add(i);\n        }\n        return result;\n    }\n    \n    /**\n     * Get all running items with instance.\n     *\n     * @return running items with instance.\n     */\n    public Map<Integer, JobInstance> getAllRunningItems() {\n        int shardingTotalCount = configService.load(true).getShardingTotalCount();\n        Map<Integer, JobInstance> result = new LinkedHashMap<>(shardingTotalCount, 1);\n        for (int i = 0; i < shardingTotalCount; i++) {\n            String data = jobNodeStorage.getJobNodeData(ShardingNode.getRunningNode(i));\n            if (!Strings.isNullOrEmpty(data)) {\n                result.put(i, new JobInstance(data));\n            }\n        }\n        return result;\n    }\n    \n    /**\n     * Set misfire flag if sharding items still running.\n     * \n     * @param items sharding items need to be set misfire flag\n     * @return is misfired for this schedule time or not\n     */\n    public boolean misfireIfHasRunningItems(final Collection<Integer> items) {\n        if (!hasRunningItems(items)) {\n            return false;\n        }\n        setMisfire(items);\n        return true;\n    }\n    \n    /**\n     * Set misfire flag if sharding items still running.\n     *\n     * @param items sharding items need to be set misfire flag\n     */\n    public void setMisfire(final Collection<Integer> items) {\n        for (int each : items) {\n            jobNodeStorage.createJobNodeIfNeeded(ShardingNode.getMisfireNode(each));\n        }\n    }\n    \n    /**\n     * Get misfired job sharding items.\n     * \n     * @param items sharding items need to be judged\n     * @return misfired job sharding items\n     */\n    public List<Integer> getMisfiredJobItems(final Collection<Integer> items) {\n        List<Integer> result = new ArrayList<>(items.size());\n        for (int each : items) {\n            if (jobNodeStorage.isJobNodeExisted(ShardingNode.getMisfireNode(each))) {\n                result.add(each);\n            }\n        }\n        return result;\n    }\n    \n    /**\n     * Clear misfire flag.\n     * \n     * @param items sharding items need to be cleared\n     */\n    public void clearMisfire(final Collection<Integer> items) {\n        for (int each : items) {\n            jobNodeStorage.removeJobNodeIfExisted(ShardingNode.getMisfireNode(each));\n        }\n    }\n    \n    /**\n     * Get disabled sharding items.\n     *\n     * @param items sharding items need to be got\n     * @return disabled sharding items\n     */\n    public List<Integer> getDisabledItems(final List<Integer> items) {\n        List<Integer> result = new ArrayList<>(items.size());\n        for (int each : items) {\n            if (jobNodeStorage.isJobNodeExisted(ShardingNode.getDisabledNode(each))) {\n                result.add(each);\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/JobInstance.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport lombok.AllArgsConstructor;\nimport lombok.EqualsAndHashCode;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.env.IpUtils;\n\nimport java.lang.management.ManagementFactory;\n\n/**\n * Job instance.\n */\n@AllArgsConstructor\n@Getter\n@Setter\n@EqualsAndHashCode(of = \"jobInstanceId\")\npublic final class JobInstance {\n    \n    public static final String DELIMITER = \"@-@\";\n    \n    private String jobInstanceId;\n    \n    private String labels;\n    \n    private String serverIp;\n    \n    public JobInstance() {\n        this(IpUtils.getIp() + DELIMITER + ManagementFactory.getRuntimeMXBean().getName().split(\"@\")[0]);\n    }\n    \n    public JobInstance(final String jobInstanceId) {\n        this(jobInstanceId, null);\n    }\n    \n    public JobInstance(final String jobInstanceId, final String labels) {\n        this(jobInstanceId, labels, IpUtils.getIp());\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/MonitorExecutionListenerManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.AbstractListenerManager;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\n/**\n * Monitor execution listener manager.\n */\npublic final class MonitorExecutionListenerManager extends AbstractListenerManager {\n    \n    private final ExecutionService executionService;\n    \n    private final ConfigurationNode configNode;\n    \n    public MonitorExecutionListenerManager(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        super(regCenter, jobName);\n        executionService = new ExecutionService(regCenter, jobName);\n        configNode = new ConfigurationNode(jobName);\n    }\n    \n    @Override\n    public void start() {\n        addDataListener(new MonitorExecutionSettingsChangedJobListener());\n    }\n    \n    class MonitorExecutionSettingsChangedJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (configNode.isConfigPath(event.getKey()) && Type.UPDATED == event.getType()\n                    && !YamlEngine.unmarshal(event.getValue(), JobConfigurationPOJO.class).toJobConfiguration().isMonitorExecution()) {\n                executionService.clearAllRunningInfo();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ShardingItemParameters.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport com.google.common.base.Strings;\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Sharding item parameters.\n */\n@Getter\npublic final class ShardingItemParameters {\n    \n    private static final String PARAMETER_DELIMITER = \",\";\n    \n    private static final String KEY_VALUE_DELIMITER = \"=\";\n    \n    private final Map<Integer, String> map;\n    \n    public ShardingItemParameters(final String shardingItemParameters) {\n        map = toMap(shardingItemParameters);\n    }\n    \n    private Map<Integer, String> toMap(final String originalShardingItemParameters) {\n        if (Strings.isNullOrEmpty(originalShardingItemParameters)) {\n            return Collections.emptyMap();\n        }\n        String[] shardingItemParameters = originalShardingItemParameters.split(PARAMETER_DELIMITER);\n        Map<Integer, String> result = new HashMap<>(shardingItemParameters.length);\n        for (String each : shardingItemParameters) {\n            ShardingItem shardingItem = parse(each, originalShardingItemParameters);\n            result.put(shardingItem.item, shardingItem.parameter);\n        }\n        return result;\n    }\n    \n    private ShardingItem parse(final String shardingItemParameter, final String originalShardingItemParameters) {\n        String[] pair = shardingItemParameter.trim().split(KEY_VALUE_DELIMITER);\n        if (2 != pair.length) {\n            throw new JobConfigurationException(\"Sharding item parameters '%s' format error, should be int=xx,int=xx\", originalShardingItemParameters);\n        }\n        try {\n            return new ShardingItem(Integer.parseInt(pair[0].trim()), pair[1].trim());\n        } catch (final NumberFormatException ex) {\n            throw new JobConfigurationException(\"Sharding item parameters key '%s' is not an integer.\", pair[0]);\n        }\n    }\n    \n    /**\n     * Sharding item.\n     */\n    @AllArgsConstructor\n    private static final class ShardingItem {\n        \n        private final int item;\n        \n        private final String parameter;\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ShardingListenerManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.AbstractListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\n/**\n * Sharding listener manager.\n */\npublic final class ShardingListenerManager extends AbstractListenerManager {\n    \n    private final String jobName;\n    \n    private final ConfigurationNode configNode;\n    \n    private final InstanceNode instanceNode;\n    \n    private final ServerNode serverNode;\n    \n    private final ShardingService shardingService;\n    \n    private final JobNodePath jobNodePath;\n    \n    private final ConfigurationService configService;\n    \n    public ShardingListenerManager(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        super(regCenter, jobName);\n        this.jobName = jobName;\n        configNode = new ConfigurationNode(jobName);\n        instanceNode = new InstanceNode(jobName);\n        serverNode = new ServerNode(jobName);\n        shardingService = new ShardingService(regCenter, jobName);\n        jobNodePath = new JobNodePath(jobName);\n        configService = new ConfigurationService(regCenter, jobName);\n    }\n    \n    @Override\n    public void start() {\n        addDataListener(new ShardingTotalCountChangedJobListener());\n        addDataListener(new ListenServersChangedJobListener());\n    }\n    \n    class ShardingTotalCountChangedJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (configNode.isConfigPath(event.getKey()) && 0 != JobRegistry.getInstance().getCurrentShardingTotalCount(jobName)) {\n                int newShardingTotalCount = YamlEngine.unmarshal(event.getValue(), JobConfigurationPOJO.class).toJobConfiguration().getShardingTotalCount();\n                if (newShardingTotalCount != JobRegistry.getInstance().getCurrentShardingTotalCount(jobName)) {\n                    shardingService.setReshardingFlag();\n                    JobRegistry.getInstance().setCurrentShardingTotalCount(jobName, newShardingTotalCount);\n                }\n            }\n        }\n    }\n    \n    class ListenServersChangedJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (!JobRegistry.getInstance().isShutdown(jobName) && (isInstanceChange(event.getType(), event.getKey()) || isServerChange(event.getKey())) && !(isStaticSharding() && hasShardingInfo())) {\n                shardingService.setReshardingFlag();\n            }\n        }\n        \n        private boolean isStaticSharding() {\n            return configService.load(true).isStaticSharding();\n        }\n        \n        private boolean hasShardingInfo() {\n            return !JobRegistry.getInstance().getRegCenter(jobName).getChildrenKeys(jobNodePath.getShardingNodePath()).isEmpty();\n        }\n        \n        private boolean isInstanceChange(final Type eventType, final String path) {\n            return instanceNode.isInstancePath(path) && Type.UPDATED != eventType;\n        }\n        \n        private boolean isServerChange(final String path) {\n            return serverNode.isServerPath(path);\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ShardingNode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\n\n/**\n * Sharding node.\n */\npublic final class ShardingNode {\n    \n    public static final String ROOT = \"sharding\";\n    \n    private static final String INSTANCE_APPENDIX = \"instance\";\n    \n    private static final String INSTANCE = ROOT + \"/%s/\" + INSTANCE_APPENDIX;\n    \n    private static final String RUNNING_APPENDIX = \"running\";\n    \n    private static final String RUNNING = ROOT + \"/%s/\" + RUNNING_APPENDIX;\n    \n    private static final String MISFIRE = ROOT + \"/%s/misfire\";\n    \n    private static final String DISABLED = ROOT + \"/%s/disabled\";\n    \n    private static final String LEADER_ROOT = LeaderNode.ROOT + \"/\" + ROOT;\n    \n    static final String NECESSARY = LEADER_ROOT + \"/necessary\";\n    \n    static final String PROCESSING = LEADER_ROOT + \"/processing\";\n    \n    private final JobNodePath jobNodePath;\n    \n    public ShardingNode(final String jobName) {\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    /**\n     * Get the path of instance node.\n     *\n     * @param item sharding item\n     * @return the path of instance node\n     */\n    public static String getInstanceNode(final int item) {\n        return String.format(INSTANCE, item);\n    }\n    \n    /**\n     * Get job running node.\n     *\n     * @param item sharding item\n     * @return job running node\n     */\n    public static String getRunningNode(final int item) {\n        return String.format(RUNNING, item);\n    }\n    \n    static String getMisfireNode(final int item) {\n        return String.format(MISFIRE, item);\n    }\n    \n    static String getDisabledNode(final int item) {\n        return String.format(DISABLED, item);\n    }\n    \n    /**\n     * Get item by running item path.\n     *\n     * @param path running item path\n     * @return running item, return null if sharding item is not running\n     */\n    public Integer getItemByRunningItemPath(final String path) {\n        if (!isRunningItemPath(path)) {\n            return null;\n        }\n        return Integer.parseInt(path.substring(jobNodePath.getFullPath(ROOT).length() + 1, path.lastIndexOf(RUNNING_APPENDIX) - 1));\n    }\n    \n    private boolean isRunningItemPath(final String path) {\n        return path.startsWith(jobNodePath.getFullPath(ROOT)) && path.endsWith(RUNNING_APPENDIX);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ShardingService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.util.BlockUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.JobShardingStrategy;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.base.transaction.TransactionOperation;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n/**\n * Sharding service.\n */\n@Slf4j\npublic final class ShardingService {\n    \n    private final String jobName;\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    private final LeaderService leaderService;\n    \n    private final ConfigurationService configService;\n    \n    private final InstanceService instanceService;\n    \n    private final InstanceNode instanceNode;\n    \n    private final ServerService serverService;\n    \n    private final ExecutionService executionService;\n    \n    private final JobNodePath jobNodePath;\n    \n    public ShardingService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        this.jobName = jobName;\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        leaderService = new LeaderService(regCenter, jobName);\n        configService = new ConfigurationService(regCenter, jobName);\n        instanceService = new InstanceService(regCenter, jobName);\n        instanceNode = new InstanceNode(jobName);\n        serverService = new ServerService(regCenter, jobName);\n        executionService = new ExecutionService(regCenter, jobName);\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    /**\n     * Set resharding flag.\n     */\n    public void setReshardingFlag() {\n        if (!leaderService.isLeaderUntilBlock()) {\n            return;\n        }\n        jobNodeStorage.createJobNodeIfNeeded(ShardingNode.NECESSARY);\n    }\n    \n    /**\n     * Judge is need resharding or not.\n     * \n     * @return is need resharding or not\n     */\n    public boolean isNeedSharding() {\n        return jobNodeStorage.isJobNodeExisted(ShardingNode.NECESSARY);\n    }\n    \n    /**\n     * Sharding if necessary.\n     * \n     * <p>\n     * Sharding if current job server is leader server;\n     * Do not sharding if no available job server. \n     * </p>\n     */\n    public void shardingIfNecessary() {\n        List<JobInstance> availableJobInstances = instanceService.getAvailableJobInstances();\n        if (!isNeedSharding() || availableJobInstances.isEmpty()) {\n            return;\n        }\n        if (!leaderService.isLeaderUntilBlock()) {\n            blockUntilShardingCompleted();\n            return;\n        }\n        waitingOtherShardingItemCompleted();\n        JobConfiguration jobConfig = configService.load(false);\n        int shardingTotalCount = jobConfig.getShardingTotalCount();\n        log.debug(\"Job '{}' sharding begin.\", jobName);\n        jobNodeStorage.fillEphemeralJobNode(ShardingNode.PROCESSING, \"\");\n        resetShardingInfo(shardingTotalCount);\n        JobShardingStrategy jobShardingStrategy = TypedSPILoader.getService(JobShardingStrategy.class, jobConfig.getJobShardingStrategyType());\n        jobNodeStorage.executeInTransaction(getShardingResultTransactionOperations(jobShardingStrategy.sharding(availableJobInstances, jobName, shardingTotalCount)));\n        log.debug(\"Job '{}' sharding complete.\", jobName);\n    }\n    \n    private void blockUntilShardingCompleted() {\n        while (!leaderService.isLeaderUntilBlock() && (jobNodeStorage.isJobNodeExisted(ShardingNode.NECESSARY) || jobNodeStorage.isJobNodeExisted(ShardingNode.PROCESSING))) {\n            log.debug(\"Job '{}' sleep short time until sharding completed.\", jobName);\n            BlockUtils.waitingShortTime();\n        }\n    }\n    \n    private void waitingOtherShardingItemCompleted() {\n        while (executionService.hasRunningItems()) {\n            log.debug(\"Job '{}' sleep short time until other job completed.\", jobName);\n            BlockUtils.waitingShortTime();\n        }\n    }\n    \n    private void resetShardingInfo(final int shardingTotalCount) {\n        for (int i = 0; i < shardingTotalCount; i++) {\n            jobNodeStorage.removeJobNodeIfExisted(ShardingNode.getInstanceNode(i));\n            jobNodeStorage.createJobNodeIfNeeded(ShardingNode.ROOT + \"/\" + i);\n        }\n        int actualShardingTotalCount = jobNodeStorage.getJobNodeChildrenKeys(ShardingNode.ROOT).size();\n        if (actualShardingTotalCount > shardingTotalCount) {\n            for (int i = shardingTotalCount; i < actualShardingTotalCount; i++) {\n                jobNodeStorage.removeJobNodeIfExisted(ShardingNode.ROOT + \"/\" + i);\n            }\n        }\n    }\n    \n    private List<TransactionOperation> getShardingResultTransactionOperations(final Map<JobInstance, List<Integer>> shardingResults) {\n        List<TransactionOperation> result = new ArrayList<>(shardingResults.size() + 2);\n        for (Entry<JobInstance, List<Integer>> entry : shardingResults.entrySet()) {\n            for (int shardingItem : entry.getValue()) {\n                String key = jobNodePath.getFullPath(ShardingNode.getInstanceNode(shardingItem));\n                String value = new String(entry.getKey().getJobInstanceId().getBytes(), StandardCharsets.UTF_8);\n                result.add(TransactionOperation.opAdd(key, value));\n            }\n        }\n        result.add(TransactionOperation.opDelete(jobNodePath.getFullPath(ShardingNode.NECESSARY)));\n        result.add(TransactionOperation.opDelete(jobNodePath.getFullPath(ShardingNode.PROCESSING)));\n        return result;\n    }\n    \n    /**\n     * Get sharding items.\n     *\n     * @param jobInstanceId job instance ID\n     * @return sharding items\n     */\n    public List<Integer> getShardingItems(final String jobInstanceId) {\n        JobInstance jobInstance = YamlEngine.unmarshal(jobNodeStorage.getJobNodeData(instanceNode.getInstancePath(jobInstanceId)), JobInstance.class);\n        if (!serverService.isAvailableServer(jobInstance.getServerIp())) {\n            return Collections.emptyList();\n        }\n        List<Integer> result = new LinkedList<>();\n        int shardingTotalCount = configService.load(true).getShardingTotalCount();\n        for (int i = 0; i < shardingTotalCount; i++) {\n            if (jobInstance.getJobInstanceId().equals(jobNodeStorage.getJobNodeData(ShardingNode.getInstanceNode(i)))) {\n                result.add(i);\n            }\n        }\n        return result;\n    }\n    \n    /**\n     * Get crashed sharding items.\n     *\n     * @param jobInstanceId crashed job instance ID\n     * @return crashed sharding items\n     */\n    public List<Integer> getCrashedShardingItems(final String jobInstanceId) {\n        String serverIp = jobInstanceId.substring(0, jobInstanceId.indexOf(JobInstance.DELIMITER));\n        if (!serverService.isEnableServer(serverIp)) {\n            return Collections.emptyList();\n        }\n        List<Integer> result = new LinkedList<>();\n        int shardingTotalCount = configService.load(true).getShardingTotalCount();\n        for (int i = 0; i < shardingTotalCount; i++) {\n            if (isRunningItem(i) && jobInstanceId.equals(jobNodeStorage.getJobNodeData(ShardingNode.getInstanceNode(i)))) {\n                result.add(i);\n            }\n        }\n        return result;\n    }\n    \n    private boolean isRunningItem(final int item) {\n        return jobNodeStorage.isJobNodeExisted(ShardingNode.getRunningNode(item));\n    }\n    \n    /**\n     * Get sharding items from localhost job server.\n     * \n     * @return sharding items from localhost job server\n     */\n    public List<Integer> getLocalShardingItems() {\n        if (JobRegistry.getInstance().isShutdown(jobName) || !serverService.isAvailableServer(JobRegistry.getInstance().getJobInstance(jobName).getServerIp())) {\n            return Collections.emptyList();\n        }\n        return getShardingItems(JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId());\n    }\n    \n    /**\n     * Query has sharding info in offline servers or not.\n     * \n     * @return has sharding info in offline servers or not\n     */\n    public boolean hasShardingInfoInOfflineServers() {\n        List<String> onlineInstances = jobNodeStorage.getJobNodeChildrenKeys(InstanceNode.ROOT);\n        int shardingTotalCount = configService.load(true).getShardingTotalCount();\n        for (int i = 0; i < shardingTotalCount; i++) {\n            if (!onlineInstances.contains(jobNodeStorage.getJobNodeData(ShardingNode.getInstanceNode(i)))) {\n                return true;\n            }\n        }\n        return false;\n    }\n    \n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/strategy/JobShardingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Job sharding strategy.\n */\npublic interface JobShardingStrategy extends TypedSPI {\n    \n    /**\n     * Sharding job.\n     * \n     * @param jobInstances all job instances which participate in sharding\n     * @param jobName job name\n     * @param shardingTotalCount sharding total count\n     * @return sharding result\n     */\n    Map<JobInstance, List<Integer>> sharding(List<JobInstance> jobInstances, String jobName, int shardingTotalCount);\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/strategy/type/AverageAllocationJobShardingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.JobShardingStrategy;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Sharding strategy which for average by sharding item.\n * \n * <p>\n * If the job server number and sharding count cannot be divided, \n * the redundant sharding item that cannot be divided will be added to the server with small sequence number in turn.\n * For example:\n * 1. If there are 3 job servers and the total sharding count is 9, each job server is divided into: 1=[0,1,2], 2=[3,4,5], 3=[6,7,8];\n * 2. If there are 3 job servers and the total sharding count is 8, each job server is divided into: 1=[0,1,6], 2=[2,3,7], 3=[4,5];\n * 3. If there are 3 job servers and the total sharding count is 10, each job server is divided into: 1=[0,1,2,9], 2=[3,4,5], 3=[6,7,8].\n * </p>\n */\npublic final class AverageAllocationJobShardingStrategy implements JobShardingStrategy {\n    \n    @Override\n    public Map<JobInstance, List<Integer>> sharding(final List<JobInstance> jobInstances, final String jobName, final int shardingTotalCount) {\n        if (jobInstances.isEmpty()) {\n            return Collections.emptyMap();\n        }\n        Map<JobInstance, List<Integer>> result = shardingAliquot(jobInstances, shardingTotalCount);\n        addAliquant(jobInstances, shardingTotalCount, result);\n        return result;\n    }\n    \n    private Map<JobInstance, List<Integer>> shardingAliquot(final List<JobInstance> shardingUnits, final int shardingTotalCount) {\n        Map<JobInstance, List<Integer>> result = new LinkedHashMap<>(shardingUnits.size(), 1);\n        int itemCountPerSharding = shardingTotalCount / shardingUnits.size();\n        int count = 0;\n        for (JobInstance each : shardingUnits) {\n            List<Integer> shardingItems = new ArrayList<>(itemCountPerSharding + 1);\n            for (int i = count * itemCountPerSharding; i < (count + 1) * itemCountPerSharding; i++) {\n                shardingItems.add(i);\n            }\n            result.put(each, shardingItems);\n            count++;\n        }\n        return result;\n    }\n    \n    private void addAliquant(final List<JobInstance> shardingUnits, final int shardingTotalCount, final Map<JobInstance, List<Integer>> shardingResults) {\n        int aliquant = shardingTotalCount % shardingUnits.size();\n        int count = 0;\n        for (Map.Entry<JobInstance, List<Integer>> entry : shardingResults.entrySet()) {\n            if (count < aliquant) {\n                entry.getValue().add(shardingTotalCount / shardingUnits.size() * shardingUnits.size() + count);\n            }\n            count++;\n        }\n    }\n    \n    @Override\n    public String getType() {\n        return \"AVG_ALLOCATION\";\n    }\n    \n    @Override\n    public boolean isDefault() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/strategy/type/OdevitySortByNameJobShardingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.JobShardingStrategy;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Sharding strategy which for hash with job name to determine IP asc or desc.\n * \n * <p>\n * IP address asc if job name' hashcode is odd;\n * IP address desc if job name' hashcode is even.\n * Used to average assign to job server.\n * For example: \n * 1. If there are 3 job servers with 2 sharding item, and the hash value of job name is odd, then each server is divided into: 1 = [0], 2 = [1], 3 = [];\n * 2. If there are 3 job servers with 2 sharding item, and the hash value of job name is even, then each server is divided into: 3 = [0], 2 = [1], 1 = [].\n * </p>\n */\npublic final class OdevitySortByNameJobShardingStrategy implements JobShardingStrategy {\n    \n    private final AverageAllocationJobShardingStrategy averageAllocationJobShardingStrategy = new AverageAllocationJobShardingStrategy();\n    \n    @Override\n    public Map<JobInstance, List<Integer>> sharding(final List<JobInstance> jobInstances, final String jobName, final int shardingTotalCount) {\n        long jobNameHash = jobName.hashCode();\n        if (0 == jobNameHash % 2) {\n            Collections.reverse(jobInstances);\n        }\n        return averageAllocationJobShardingStrategy.sharding(jobInstances, jobName, shardingTotalCount);\n    }\n    \n    @Override\n    public String getType() {\n        return \"ODEVITY\";\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/strategy/type/RoundRobinByNameJobShardingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.JobShardingStrategy;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Sharding strategy which for round robin by name job.\n */\npublic final class RoundRobinByNameJobShardingStrategy implements JobShardingStrategy {\n    \n    private final AverageAllocationJobShardingStrategy averageAllocationJobShardingStrategy = new AverageAllocationJobShardingStrategy();\n    \n    @Override\n    public Map<JobInstance, List<Integer>> sharding(final List<JobInstance> jobInstances, final String jobName, final int shardingTotalCount) {\n        return averageAllocationJobShardingStrategy.sharding(rotateServerList(jobInstances, jobName), jobName, shardingTotalCount);\n    }\n    \n    private List<JobInstance> rotateServerList(final List<JobInstance> shardingUnits, final String jobName) {\n        int shardingUnitsSize = shardingUnits.size();\n        int offset = Math.abs(jobName.hashCode()) % shardingUnitsSize;\n        if (0 == offset) {\n            return shardingUnits;\n        }\n        List<JobInstance> result = new ArrayList<>(shardingUnitsSize);\n        for (int i = 0; i < shardingUnitsSize; i++) {\n            int index = (i + offset) % shardingUnitsSize;\n            result.add(shardingUnits.get(index));\n        }\n        return result;\n    }\n    \n    @Override\n    public String getType() {\n        return \"ROUND_ROBIN\";\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/strategy/type/SingleShardingBalanceJobShardingStrategy.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.JobShardingStrategy;\n\n/**\n * Single sharding Balance strategy, referenced of ROUND_ROBIN strategy.\n * <pre>\n * it resolves the problem which ROUND_ROBIN is stick with the certain one job instance\n * for the hashcode of job name is a constant value. while with SINGLE_SHARDING_BALANCE, it allows\n * the job running on all the job instances each one by one, just like loop the job instances.\n *\n * this is the real round robin balance job running in the job instance dimension.\n * </pre>\n *\n */\npublic class SingleShardingBalanceJobShardingStrategy implements JobShardingStrategy {\n    \n    private final AverageAllocationJobShardingStrategy averageAllocationJobShardingStrategy = new AverageAllocationJobShardingStrategy();\n    \n    @Override\n    public Map<JobInstance, List<Integer>> sharding(final List<JobInstance> jobInstances, final String jobName, final int shardingTotalCount) {\n        int shardingUnitsSize = jobInstances.size();\n        int offset = Math.abs(jobName.hashCode() + ((Long) System.currentTimeMillis()).intValue()) % shardingUnitsSize;\n        \n        List<JobInstance> result = new ArrayList<>(shardingUnitsSize);\n        for (int i = 0; i < shardingUnitsSize; i++) {\n            int index = (i + offset) % shardingUnitsSize;\n            result.add(jobInstances.get(index));\n        }\n        \n        return averageAllocationJobShardingStrategy.sharding(result, jobName, shardingTotalCount);\n    }\n    \n    @Override\n    public String getType() {\n        return \"SINGLE_SHARDING_BALANCE\";\n    }\n    \n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/snapshot/SnapshotService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.snapshot;\n\nimport com.google.common.base.Preconditions;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.curator.framework.recipes.cache.ChildData;\nimport org.apache.curator.framework.recipes.cache.CuratorCache;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.util.SensitiveInfoUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * Snapshot service.\n */\n@Slf4j\npublic final class SnapshotService {\n    \n    public static final String DUMP_COMMAND = \"dump@\";\n    \n    private final int port;\n    \n    private final CoordinatorRegistryCenter regCenter;\n    \n    private ServerSocket serverSocket;\n    \n    private volatile boolean closed;\n    \n    public SnapshotService(final CoordinatorRegistryCenter regCenter, final int port) {\n        Preconditions.checkArgument(port >= 0 && port <= 0xFFFF, \"Port value out of range: \" + port);\n        this.regCenter = regCenter;\n        this.port = port;\n    }\n    \n    /**\n     * Start to listen.\n     */\n    public void listen() {\n        try {\n            log.info(\"ElasticJob: Snapshot service is running on port '{}'\", openSocket(port));\n        } catch (final IOException ex) {\n            log.error(\"ElasticJob: Snapshot service listen failure, error is: \", ex);\n        }\n    }\n    \n    private int openSocket(final int port) throws IOException {\n        closed = false;\n        serverSocket = new ServerSocket(port);\n        int localPort = serverSocket.getLocalPort();\n        String threadName = String.format(\"elasticjob-snapshot-service-%d\", localPort);\n        new Thread(() -> {\n            while (!closed) {\n                try {\n                    process(serverSocket.accept());\n                } catch (final IOException ex) {\n                    if (isIgnoredException()) {\n                        return;\n                    }\n                    log.error(\"ElasticJob: Snapshot service open socket failure, error is: \", ex);\n                }\n            }\n        }, threadName).start();\n        return localPort;\n    }\n    \n    private boolean isIgnoredException() {\n        return serverSocket.isClosed();\n    }\n    \n    private void process(final Socket socket) throws IOException {\n        try (\n                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));\n                Socket ignored = socket) {\n            String cmdLine = reader.readLine();\n            if (null != cmdLine && cmdLine.startsWith(DUMP_COMMAND) && cmdLine.split(\"@\").length == 2) {\n                String jobName = cmdLine.split(\"@\")[1];\n                String result = dumpJobDirectly(jobName);\n                outputMessage(writer, result);\n            }\n        }\n    }\n    \n    private void dumpDirectly(final String path, final String jobName, final List<String> result) {\n        for (String each : regCenter.getChildrenKeys(path)) {\n            String zkPath = path + \"/\" + each;\n            String zkValue = Optional.ofNullable(regCenter.get(zkPath)).orElse(\"\");\n            String cachePath = zkPath;\n            String cacheValue = zkValue;\n            // TODO Decoupling ZooKeeper\n            if (regCenter instanceof ZookeeperRegistryCenter) {\n                CuratorCache cache = (CuratorCache) regCenter.getRawCache(\"/\" + jobName);\n                if (null != cache) {\n                    Optional<ChildData> cacheData = cache.get(zkPath);\n                    cachePath = cacheData.map(ChildData::getPath).orElse(\"\");\n                    cacheValue = cacheData.map(ChildData::getData).map(String::new).orElse(\"\");\n                }\n            }\n            if (zkValue.equals(cacheValue) && zkPath.equals(cachePath)) {\n                result.add(String.join(\" | \", zkPath, zkValue));\n            } else {\n                result.add(String.join(\" | \", zkPath, zkValue, cachePath, cacheValue));\n            }\n            dumpDirectly(zkPath, jobName, result);\n        }\n    }\n    \n    /**\n     * Dump job.\n     * @param jobName job's name\n     * @return dump job's info\n     */\n    public String dumpJobDirectly(final String jobName) {\n        String path = \"/\" + jobName;\n        final List<String> result = new ArrayList<>();\n        dumpDirectly(path, jobName, result);\n        return String.join(\"\\n\", SensitiveInfoUtils.filterSensitiveIps(result)) + \"\\n\";\n    }\n    \n    /**\n     * Dump job.\n     * @param instanceIp job instance ip addr\n     * @param dumpPort dump port\n     * @param jobName job's name\n     * @return dump job's info\n     * @throws IOException i/o exception\n     */\n    public static String dumpJob(final String instanceIp, final int dumpPort, final String jobName) throws IOException {\n        try (\n                Socket socket = new Socket(instanceIp, dumpPort);\n                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {\n            writer.write(DUMP_COMMAND + jobName);\n            writer.newLine();\n            writer.flush();\n            StringBuilder sb = new StringBuilder();\n            String line;\n            while (null != (line = reader.readLine())) {\n                sb.append(line).append(\"\\n\");\n            }\n            return sb.toString();\n        }\n    }\n    \n    private void outputMessage(final BufferedWriter outputWriter, final String msg) throws IOException {\n        outputWriter.append(msg);\n        outputWriter.flush();\n    }\n    \n    /**\n     * Close listener.\n     */\n    public void close() {\n        closed = true;\n        if (null != serverSocket && !serverSocket.isClosed()) {\n            try {\n                serverSocket.close();\n            } catch (final IOException ex) {\n                log.error(\"ElasticJob: Snapshot service close failure, error is: \", ex);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/storage/JobNodePath.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.storage;\n\nimport lombok.RequiredArgsConstructor;\n\n/**\n * Job node path.\n * \n * <p>\n * Job node is add job name as prefix.\n * </p>\n */\n@RequiredArgsConstructor\npublic final class JobNodePath {\n    \n    private static final String LEADER_HOST_NODE = \"leader/election/instance\";\n    \n    private static final String CONFIG_NODE = \"config\";\n    \n    private static final String SERVERS_NODE = \"servers\";\n    \n    private static final String INSTANCES_NODE = \"instances\";\n    \n    private static final String SHARDING_NODE = \"sharding\";\n    \n    private final String jobName;\n    \n    /**\n     * Get full path.\n     * \n     * @param node node\n     * @return full path\n     */\n    public String getFullPath(final String node) {\n        return String.format(\"/%s/%s\", jobName, node);\n    }\n    \n    /**\n     * Get configuration node path.\n     *\n     * @return configuration node path\n     */\n    public String getConfigNodePath() {\n        return String.format(\"/%s/%s\", jobName, CONFIG_NODE);\n    }\n    \n    /**\n     * Get leader host node path.\n     *\n     * @return leader host node path\n     */\n    public String getLeaderHostNodePath() {\n        return String.format(\"/%s/%s\", jobName, LEADER_HOST_NODE);\n    }\n    \n    /**\n     * Get server node path.\n     *\n     * @return server node path\n     */\n    public String getServerNodePath() {\n        return String.format(\"/%s/%s\", jobName, SERVERS_NODE);\n    }\n    \n    /**\n     * Get server node path.\n     *\n     * @param serverIp server IP address\n     * @return server node path\n     */\n    public String getServerNodePath(final String serverIp) {\n        return String.format(\"%s/%s\", getServerNodePath(), serverIp);\n    }\n    \n    /**\n     * Get instances node path.\n     *\n     * @return instances node path\n     */\n    public String getInstancesNodePath() {\n        return String.format(\"/%s/%s\", jobName, INSTANCES_NODE);\n    }\n    \n    /**\n     * Get instance node path via job instance ID.\n     *\n     * @param instanceId instance ID\n     * @return instance node path\n     */\n    public String getInstanceNodePath(final String instanceId) {\n        return String.format(\"%s/%s\", getInstancesNodePath(), instanceId);\n    }\n    \n    /**\n     * Get sharding node path.\n     *\n     * @return sharding node path\n     */\n    public String getShardingNodePath() {\n        return String.format(\"/%s/%s\", jobName, SHARDING_NODE);\n    }\n    \n    /**\n     * Get sharding node path.\n     *\n     * @param item sharding item\n     * @param nodeName node name\n     * @return sharding node path\n     */\n    public String getShardingNodePath(final String item, final String nodeName) {\n        return String.format(\"%s/%s/%s\", getShardingNodePath(), item, nodeName);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/storage/JobNodeStorage.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.storage;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.ListenerNotifierManager;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.base.LeaderExecutionCallback;\nimport org.apache.shardingsphere.elasticjob.reg.base.transaction.TransactionOperation;\nimport org.apache.shardingsphere.elasticjob.reg.exception.RegExceptionHandler;\nimport org.apache.shardingsphere.elasticjob.reg.listener.ConnectionStateChangedEventListener;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Executor;\n\n/**\n * Job node storage.\n */\npublic final class JobNodeStorage {\n    \n    private final CoordinatorRegistryCenter regCenter;\n    \n    private final String jobName;\n    \n    private final JobNodePath jobNodePath;\n    \n    public JobNodeStorage(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        this.regCenter = regCenter;\n        this.jobName = jobName;\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    /**\n     * Judge is job node existed or not.\n     * \n     * @param node node\n     * @return is job node existed or not\n     */\n    public boolean isJobNodeExisted(final String node) {\n        return regCenter.isExisted(jobNodePath.getFullPath(node));\n    }\n    \n    /**\n     * Judge is job root node existed or not.\n     *\n     * @return is job root node existed or not\n     */\n    public boolean isJobRootNodeExisted() {\n        return regCenter.isExisted(\"/\" + jobName);\n    }\n    \n    /**\n     * Get job node data.\n     * \n     * @param node node\n     * @return data of job node\n     */\n    public String getJobNodeData(final String node) {\n        return regCenter.get(jobNodePath.getFullPath(node));\n    }\n    \n    /**\n     * Get job node data from registry center directly.\n     * \n     * @param node node\n     * @return data of job node\n     */\n    public String getJobNodeDataDirectly(final String node) {\n        return regCenter.getDirectly(jobNodePath.getFullPath(node));\n    }\n    \n    /**\n     * Get job node children keys.\n     * \n     * @param node node\n     * @return children keys\n     */\n    public List<String> getJobNodeChildrenKeys(final String node) {\n        return regCenter.getChildrenKeys(jobNodePath.getFullPath(node));\n    }\n    \n    /**\n     * Get job root node data.\n     *\n     * @return data of job node\n     */\n    public String getJobRootNodeData() {\n        return regCenter.get(\"/\" + jobName);\n    }\n    \n    /**\n     * Create job node if needed.\n     * \n     * <p>Do not create node if root node not existed, which means job is shutdown.</p>\n     * \n     * @param node node\n     */\n    public void createJobNodeIfNeeded(final String node) {\n        if (isJobRootNodeExisted() && !isJobNodeExisted(node)) {\n            regCenter.persist(jobNodePath.getFullPath(node), \"\");\n        }\n    }\n    \n    /**\n     * Remove job node if existed.\n     * \n     * @param node node\n     */\n    public void removeJobNodeIfExisted(final String node) {\n        if (isJobNodeExisted(node)) {\n            regCenter.remove(jobNodePath.getFullPath(node));\n        }\n    }\n    \n    /**\n     * Fill job node.\n     *\n     * @param node node\n     * @param value data of job node\n     */\n    public void fillJobNode(final String node, final Object value) {\n        regCenter.persist(jobNodePath.getFullPath(node), value.toString());\n    }\n    \n    /**\n     * Fill ephemeral job node.\n     * \n     * @param node node\n     * @param value data of job node\n     */\n    public void fillEphemeralJobNode(final String node, final Object value) {\n        regCenter.persistEphemeral(jobNodePath.getFullPath(node), value.toString());\n    }\n    \n    /**\n     * Update job node.\n     * \n     * @param node node\n     * @param value data of job node\n     */\n    public void updateJobNode(final String node, final Object value) {\n        regCenter.update(jobNodePath.getFullPath(node), value.toString());\n    }\n    \n    /**\n     * Replace data.\n     * \n     * @param node node\n     * @param value to be replaced data\n     */\n    public void replaceJobNode(final String node, final Object value) {\n        regCenter.persist(jobNodePath.getFullPath(node), value.toString());\n    }\n    \n    /**\n     * Replace data to root node.\n     *\n     * @param value to be replaced data\n     */\n    public void replaceJobRootNode(final Object value) {\n        regCenter.persist(\"/\" + jobName, value.toString());\n    }\n    \n    /**\n     * Execute operations in transaction.\n     * \n     * @param transactionOperations operations to be executed in transaction\n     */\n    public void executeInTransaction(final List<TransactionOperation> transactionOperations) {\n        List<TransactionOperation> result = new ArrayList<>(transactionOperations.size() + 1);\n        result.add(TransactionOperation.opCheckExists(\"/\"));\n        result.addAll(transactionOperations);\n        try {\n            regCenter.executeInTransaction(result);\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n    }\n    \n    /**\n     * Execute in leader server.\n     * \n     * @param latchNode node for leader latch\n     * @param callback execute callback\n     */\n    public void executeInLeader(final String latchNode, final LeaderExecutionCallback callback) {\n        regCenter.executeInLeader(jobNodePath.getFullPath(latchNode), callback);\n    }\n    \n    /**\n     * Add connection state listener.\n     * \n     * @param listener connection state listener\n     */\n    public void addConnectionStateListener(final ConnectionStateChangedEventListener listener) {\n        regCenter.addConnectionStateChangedEventListener(\"/\" + jobName, listener);\n    }\n    \n    /**\n     * Add data listener.\n     * \n     * @param listener data listener\n     */\n    public void addDataListener(final DataChangedEventListener listener) {\n        Executor executor = ListenerNotifierManager.getInstance().getJobNotifyExecutor(jobName);\n        regCenter.watch(\"/\" + jobName, listener, executor);\n    }\n    \n    /**\n     * Get registry center time.\n     * \n     * @return registry center time\n     */\n    public long getRegistryCenterTime() {\n        return regCenter.getRegistryCenterTime(jobNodePath.getFullPath(\"systemTime/current\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/trigger/TriggerListenerManager.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.trigger;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.AbstractListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\n/**\n * Job trigger listener manager.\n */\npublic final class TriggerListenerManager extends AbstractListenerManager {\n    \n    private final String jobName;\n    \n    private final TriggerNode triggerNode;\n    \n    private final TriggerService triggerService;\n    \n    public TriggerListenerManager(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        super(regCenter, jobName);\n        this.jobName = jobName;\n        triggerNode = new TriggerNode(jobName);\n        triggerService = new TriggerService(regCenter, jobName);\n    }\n    \n    @Override\n    public void start() {\n        addDataListener(new JobTriggerStatusJobListener());\n    }\n    \n    class JobTriggerStatusJobListener implements DataChangedEventListener {\n        \n        @Override\n        public void onChange(final DataChangedEvent event) {\n            if (!triggerNode.isLocalTriggerPath(event.getKey()) || Type.ADDED != event.getType()) {\n                return;\n            }\n            triggerService.removeTriggerFlag();\n            if (!JobRegistry.getInstance().isShutdown(jobName) && !JobRegistry.getInstance().isJobRunning(jobName)) {\n                // TODO At present, it cannot be triggered when the job is running, and it will be changed to a stacked trigger in the future.\n                JobRegistry.getInstance().getJobScheduleController(jobName).triggerJob();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/trigger/TriggerNode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.trigger;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\n\n/**\n * Trigger node.\n */\npublic final class TriggerNode {\n    \n    public static final String ROOT = \"trigger\";\n    \n    private static final String TRIGGER = ROOT + \"/%s\";\n    \n    private final String jobName;\n    \n    private final JobNodePath jobNodePath;\n    \n    public TriggerNode(final String jobName) {\n        this.jobName = jobName;\n        jobNodePath = new JobNodePath(jobName);\n    }\n    \n    /**\n     * Is local trigger path.\n     *\n     * @param path path\n     * @return is local trigger path or not\n     */\n    public boolean isLocalTriggerPath(final String path) {\n        JobInstance jobInstance = JobRegistry.getInstance().getJobInstance(jobName);\n        return null != jobInstance && path.equals(jobNodePath.getFullPath(String.format(TRIGGER, jobInstance.getJobInstanceId())));\n    }\n    \n    /**\n     * Get local trigger path.\n     *\n     * @return local trigger path\n     */\n    public String getLocalTriggerPath() {\n        return getTriggerPath(JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId());\n    }\n    \n    /**\n     * Get trigger path.\n     *\n     * @param instanceId instance id\n     * @return trigger path\n     */\n    public String getTriggerPath(final String instanceId) {\n        return String.format(TRIGGER, instanceId);\n    }\n    \n    /**\n     * Get trigger root.\n     *\n     * @return trigger root\n     */\n    public String getTriggerRoot() {\n        return ROOT;\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/internal/trigger/TriggerService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.trigger;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\n/**\n * Trigger service.\n */\npublic final class TriggerService {\n    \n    private final JobNodeStorage jobNodeStorage;\n    \n    private final TriggerNode triggerNode;\n    \n    public TriggerService(final CoordinatorRegistryCenter regCenter, final String jobName) {\n        jobNodeStorage = new JobNodeStorage(regCenter, jobName);\n        triggerNode = new TriggerNode(jobName);\n    }\n    \n    /**\n     * Remove trigger flag.\n     */\n    public void removeTriggerFlag() {\n        jobNodeStorage.removeJobNodeIfExisted(triggerNode.getLocalTriggerPath());\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/listener/AbstractDistributeOnceElasticJobListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.listener;\n\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.util.BlockUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.time.TimeService;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.guarantee.GuaranteeService;\n\nimport java.util.Set;\n\n/**\n * Distributed once ElasticJob listener.\n */\npublic abstract class AbstractDistributeOnceElasticJobListener implements ElasticJobListener {\n    \n    private final long startedTimeoutMilliseconds;\n    \n    private final Object startedWait = new Object();\n    \n    private final long completedTimeoutMilliseconds;\n    \n    private final Object completedWait = new Object();\n    \n    @Setter\n    private GuaranteeService guaranteeService;\n    \n    private final TimeService timeService = new TimeService();\n    \n    public AbstractDistributeOnceElasticJobListener(final long startedTimeoutMilliseconds, final long completedTimeoutMilliseconds) {\n        this.startedTimeoutMilliseconds = startedTimeoutMilliseconds <= 0L ? Long.MAX_VALUE : startedTimeoutMilliseconds;\n        this.completedTimeoutMilliseconds = completedTimeoutMilliseconds <= 0L ? Long.MAX_VALUE : completedTimeoutMilliseconds;\n    }\n    \n    @Override\n    public final void beforeJobExecuted(final ShardingContexts shardingContexts) {\n        Set<Integer> shardingItems = shardingContexts.getShardingItemParameters().keySet();\n        if (shardingItems.isEmpty()) {\n            return;\n        }\n        guaranteeService.registerStart(shardingItems);\n        while (!guaranteeService.isRegisterStartSuccess(shardingItems)) {\n            BlockUtils.waitingShortTime();\n        }\n        if (guaranteeService.isAllStarted()) {\n            guaranteeService.executeInLeaderForLastStarted(this, shardingContexts);\n            return;\n        }\n        long before = timeService.getCurrentMillis();\n        try {\n            synchronized (startedWait) {\n                startedWait.wait(startedTimeoutMilliseconds);\n            }\n        } catch (final InterruptedException ex) {\n            Thread.interrupted();\n        }\n        if (timeService.getCurrentMillis() - before >= startedTimeoutMilliseconds) {\n            guaranteeService.clearAllStartedInfo();\n            handleTimeout(startedTimeoutMilliseconds);\n        }\n    }\n    \n    @Override\n    public final void afterJobExecuted(final ShardingContexts shardingContexts) {\n        Set<Integer> shardingItems = shardingContexts.getShardingItemParameters().keySet();\n        if (shardingItems.isEmpty()) {\n            return;\n        }\n        guaranteeService.registerComplete(shardingItems);\n        while (!guaranteeService.isRegisterCompleteSuccess(shardingItems)) {\n            BlockUtils.waitingShortTime();\n        }\n        if (guaranteeService.isAllCompleted()) {\n            guaranteeService.executeInLeaderForLastCompleted(this, shardingContexts);\n            return;\n        }\n        long before = timeService.getCurrentMillis();\n        try {\n            synchronized (completedWait) {\n                completedWait.wait(completedTimeoutMilliseconds);\n            }\n        } catch (final InterruptedException ex) {\n            Thread.interrupted();\n        }\n        if (timeService.getCurrentMillis() - before >= completedTimeoutMilliseconds) {\n            guaranteeService.clearAllCompletedInfo();\n            handleTimeout(completedTimeoutMilliseconds);\n        }\n    }\n    \n    private void handleTimeout(final long timeoutMilliseconds) {\n        throw new JobSystemException(\"Job timeout. timeout mills is %s.\", timeoutMilliseconds);\n    }\n    \n    /**\n     * Do before job executed at last sharding job started.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    public abstract void doBeforeJobExecutedAtLastStarted(ShardingContexts shardingContexts);\n    \n    /**\n     * Do after job executed at last sharding job completed.\n     *\n     * @param shardingContexts sharding contexts\n     */\n    public abstract void doAfterJobExecutedAtLastCompleted(ShardingContexts shardingContexts);\n    \n    /**\n     * Notify waiting task start.\n     */\n    public void notifyWaitingTaskStart() {\n        synchronized (startedWait) {\n            startedWait.notifyAll();\n        }\n    }\n    \n    /**\n     * Notify waiting task complete.\n     */\n    public void notifyWaitingTaskComplete() {\n        synchronized (completedWait) {\n            completedWait.notifyAll();\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/tracing/config/TracingConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.config;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.api.JobExtraConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.storage.TracingStorageConverterFactory;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\nimport org.apache.shardingsphere.infra.spi.exception.ServiceProviderNotFoundException;\n\n/**\n * Tracing configuration.\n *\n * @param <T> type of tracing storage\n */\n@RequiredArgsConstructor\n@Getter\npublic final class TracingConfiguration<T> implements JobExtraConfiguration {\n    \n    private final String type;\n    \n    private final TracingStorageConfiguration<T> tracingStorageConfiguration;\n    \n    @SuppressWarnings(\"unchecked\")\n    public TracingConfiguration(final String type, final T storage) {\n        this.type = type;\n        tracingStorageConfiguration = TracingStorageConverterFactory.findConverter((Class<T>) storage.getClass())\n                .orElseThrow(() -> new ServiceProviderNotFoundException(storage.getClass(), storage.getClass().getSimpleName())).toConfiguration(storage);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/tracing/event/JobTracingEventBus.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.event;\n\nimport com.google.common.eventbus.AsyncEventBus;\nimport com.google.common.eventbus.EventBus;\nimport com.google.common.util.concurrent.MoreExecutors;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.concurrent.BasicThreadFactory;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.exception.TracingConfigurationException;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListenerFactory;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobEvent;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Job tracing event bus.\n */\n@Slf4j\npublic final class JobTracingEventBus {\n    \n    private static final ExecutorService EXECUTOR_SERVICE;\n    \n    private final EventBus eventBus;\n    \n    private volatile boolean isRegistered;\n    \n    static {\n        EXECUTOR_SERVICE = createExecutorService(Runtime.getRuntime().availableProcessors() * 2);\n    }\n    \n    public JobTracingEventBus() {\n        eventBus = null;\n    }\n    \n    public JobTracingEventBus(final TracingConfiguration<?> tracingConfig) {\n        eventBus = new AsyncEventBus(EXECUTOR_SERVICE);\n        register(tracingConfig);\n    }\n    \n    private static ExecutorService createExecutorService(final int threadSize) {\n        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(threadSize, threadSize, 5L, TimeUnit.MINUTES,\n                new LinkedBlockingQueue<>(), new BasicThreadFactory.Builder().namingPattern(String.join(\"-\", \"job-event\", \"%s\")).build());\n        threadPoolExecutor.allowCoreThreadTimeOut(true);\n        return MoreExecutors.listeningDecorator(MoreExecutors.getExitingExecutorService(threadPoolExecutor));\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    private void register(final TracingConfiguration<?> tracingConfig) {\n        try {\n            if (null == tracingConfig.getTracingStorageConfiguration()) {\n                throw new TracingConfigurationException(String.format(\"Can not find executor service handler type '%s'.\", tracingConfig.getType()));\n            }\n            eventBus.register(\n                    TypedSPILoader.getService(TracingListenerFactory.class, tracingConfig.getType()).create(tracingConfig.getTracingStorageConfiguration().getStorage()));\n            isRegistered = true;\n        } catch (final TracingConfigurationException ex) {\n            log.error(\"Elastic job: create tracing listener failure, error is: \", ex);\n        }\n    }\n    \n    /**\n     * Post event.\n     *\n     * @param event job event\n     */\n    public void post(final JobEvent event) {\n        if (isRegistered && !EXECUTOR_SERVICE.isShutdown()) {\n            eventBus.post(event);\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/tracing/exception/TracingStorageUnavailableException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.exception;\n\n/**\n * Tracing storage unavailable exception.\n */\npublic final class TracingStorageUnavailableException extends RuntimeException {\n    \n    private static final long serialVersionUID = 7364942870490687255L;\n    \n    public TracingStorageUnavailableException(final Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/tracing/storage/TracingStorageConverterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.storage;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfigurationConverter;\nimport org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;\n\nimport java.util.Optional;\n\n/**\n * Factory for {@link TracingStorageConfigurationConverter}.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class TracingStorageConverterFactory {\n    \n    /**\n     * Find {@link TracingStorageConfigurationConverter} for specific storage type.\n     *\n     * @param storageType storage type\n     * @param <T> storage type\n     * @return instance of {@link TracingStorageConfigurationConverter}\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> Optional<TracingStorageConfigurationConverter<T>> findConverter(final Class<T> storageType) {\n        return ShardingSphereServiceLoader.getServiceInstances(TracingStorageConfigurationConverter.class).stream()\n                .filter(each -> each.storageType().isAssignableFrom(storageType)).map(each -> (TracingStorageConfigurationConverter<T>) each).findFirst();\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/tracing/yaml/YamlTracingConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.yaml;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\n\n/**\n * YAML configuration for {@link TracingConfiguration}.\n *\n * @param <T> type of storage\n */\n@Getter\n@Setter\npublic final class YamlTracingConfiguration<T> implements YamlConfiguration<TracingConfiguration<T>> {\n    \n    private static final long serialVersionUID = -6625535892000287729L;\n    \n    private String type;\n    \n    private YamlTracingStorageConfiguration<T> tracingStorageConfiguration;\n    \n    @Override\n    public TracingConfiguration<T> toConfiguration() {\n        return new TracingConfiguration<>(type, tracingStorageConfiguration.toConfiguration());\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/tracing/yaml/YamlTracingConfigurationConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.yaml;\n\nimport org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfigurationConverter;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\n\n/**\n * Converter to convert {@link TracingConfiguration} to {@link YamlTracingConfiguration}.\n *\n * @param <T> type of storage\n */\n@SuppressWarnings({\"rawtypes\", \"unchecked\"})\npublic final class YamlTracingConfigurationConverter<T> implements YamlConfigurationConverter<TracingConfiguration<T>, YamlTracingConfiguration<T>> {\n    \n    @Override\n    public YamlTracingConfiguration<T> convertToYamlConfiguration(final TracingConfiguration<T> tracingConfig) {\n        YamlTracingConfiguration<T> result = new YamlTracingConfiguration<>();\n        result.setType(tracingConfig.getType());\n        result.setTracingStorageConfiguration(convertTracingStorageConfiguration(tracingConfig.getTracingStorageConfiguration()));\n        return result;\n    }\n    \n    private YamlTracingStorageConfiguration<T> convertTracingStorageConfiguration(final TracingStorageConfiguration<T> tracingStorageConfig) {\n        return (YamlTracingStorageConfiguration) TypedSPILoader.getService(YamlConfigurationConverter.class, tracingStorageConfig.getClass()).convertToYamlConfiguration(tracingStorageConfig);\n    }\n    \n    @Override\n    public Class getType() {\n        return TracingConfiguration.class;\n    }\n}\n"
  },
  {
    "path": "kernel/src/main/java/org/apache/shardingsphere/elasticjob/kernel/tracing/yaml/YamlTracingStorageConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.yaml;\n\nimport org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\n\n/**\n * YAML configuration for {@link TracingStorageConfiguration}.\n *\n * @param <T> type of storage\n */\npublic interface YamlTracingStorageConfiguration<T> extends YamlConfiguration<TracingStorageConfiguration<T>> {\n}\n"
  },
  {
    "path": "kernel/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.JobExecutorThreadPoolSizeProvider",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.kernel.executor.threadpool.type.CPUUsageJobExecutorThreadPoolSizeProvider\norg.apache.shardingsphere.elasticjob.kernel.executor.threadpool.type.SingleThreadJobExecutorThreadPoolSizeProvider\n"
  },
  {
    "path": "kernel/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.JobShardingStrategy",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type.AverageAllocationJobShardingStrategy\norg.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type.OdevitySortByNameJobShardingStrategy\norg.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type.RoundRobinByNameJobShardingStrategy\norg.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type.SingleShardingBalanceJobShardingStrategy\n"
  },
  {
    "path": "kernel/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfigurationConverter",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfigurationConverter\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/ElasticJobExecutorTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.facade.JobFacade;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.executor.ClassedFooJobExecutor;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.job.FooJob;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionEnvironmentException;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent.State;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport org.mockito.junit.jupiter.MockitoSettings;\nimport org.mockito.quality.Strictness;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyBoolean;\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.lenient;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\n@MockitoSettings(strictness = Strictness.LENIENT)\nclass ElasticJobExecutorTest {\n    \n    @Mock\n    private FooJob fooJob;\n    \n    private JobConfiguration jobConfig;\n    \n    @Mock\n    private JobFacade jobFacade;\n    \n    @Mock\n    private JobRuntimeService jobRuntimeService;\n    \n    @Mock\n    private ClassedFooJobExecutor jobItemExecutor;\n    \n    private ElasticJobExecutor elasticJobExecutor;\n    \n    @BeforeEach\n    void setUp() {\n        jobConfig = createJobConfiguration();\n        when(jobFacade.loadJobConfiguration(anyBoolean())).thenReturn(jobConfig);\n        when(jobFacade.getJobRuntimeService()).thenReturn(jobRuntimeService);\n        elasticJobExecutor = new ElasticJobExecutor(fooJob, jobConfig, jobFacade);\n        ReflectionUtils.setFieldValue(elasticJobExecutor, \"jobItemExecutor\", jobItemExecutor);\n    }\n    \n    private JobConfiguration createJobConfiguration() {\n        return JobConfiguration.newBuilder(\"test_job\", 3)\n                .cron(\"0/1 * * * * ?\").shardingItemParameters(\"0=A,1=B,2=C\").jobParameter(\"param\").failover(true).misfire(false).jobErrorHandlerType(\"FOO\").description(\"desc\").build();\n    }\n    \n    @Test\n    void assertExecuteWhenCheckMaxTimeDiffSecondsIntolerable() {\n        assertThrows(JobSystemException.class, () -> {\n            doThrow(JobExecutionEnvironmentException.class).when(jobFacade).checkJobExecutionEnvironment();\n            try {\n                elasticJobExecutor.execute();\n            } finally {\n                verify(jobItemExecutor, times(0)).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n            }\n        });\n    }\n    \n    @Test\n    void assertExecuteWhenPreviousJobStillRunning() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 3, \"\", Collections.emptyMap());\n        when(jobFacade.getShardingContexts()).thenReturn(shardingContexts);\n        when(jobFacade.misfireIfRunning(shardingContexts.getShardingItemParameters().keySet())).thenReturn(true);\n        elasticJobExecutor.execute();\n        verify(jobFacade).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_STAGING, \"Job 'test_job' execute begin.\");\n        verify(jobFacade).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_FINISHED,\n                \"Previous job 'test_job' - shardingItems '[]' is still running, misfired job will start after previous job completed.\");\n        verify(jobItemExecutor, times(0)).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n    }\n    \n    @Test\n    void assertExecuteWhenShardingItemsIsEmpty() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 3, \"\", Collections.emptyMap());\n        prepareForIsNotMisfire(jobFacade, shardingContexts);\n        elasticJobExecutor.execute();\n        verify(jobFacade).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_STAGING, \"Job 'test_job' execute begin.\");\n        verify(jobFacade).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_FINISHED, \"Sharding item for job 'test_job' is empty.\");\n        verify(jobItemExecutor, times(0)).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n    }\n    \n    @Test\n    void assertExecuteFailureWhenThrowExceptionForSingleShardingItem() {\n        assertThrows(JobSystemException.class, () -> assertExecuteFailureWhenThrowException(createSingleShardingContexts()));\n    }\n    \n    @Test\n    void assertExecuteFailureWhenThrowExceptionForMultipleShardingItems() {\n        assertExecuteFailureWhenThrowException(createMultipleShardingContexts());\n    }\n    \n    private void assertExecuteFailureWhenThrowException(final ShardingContexts shardingContexts) {\n        prepareForIsNotMisfire(jobFacade, shardingContexts);\n        doThrow(RuntimeException.class).when(jobItemExecutor).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n        try {\n            elasticJobExecutor.execute();\n        } finally {\n            verify(jobFacade).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_STAGING, \"Job 'test_job' execute begin.\");\n            verify(jobFacade).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_RUNNING, \"\");\n            verify(jobFacade).postJobStatusTraceEvent(eq(shardingContexts.getTaskId()), eq(State.TASK_ERROR), argThat(msg -> isValidErrorMessage(msg, shardingContexts)));\n            verify(jobFacade).registerJobBegin(shardingContexts);\n            verify(jobItemExecutor, times(shardingContexts.getShardingTotalCount())).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n            verify(jobFacade).registerJobCompleted(shardingContexts);\n        }\n    }\n    \n    private boolean isValidErrorMessage(final String errorMessage, final ShardingContexts shardingContexts) {\n        if (1 == shardingContexts.getShardingItemParameters().size()) {\n            return (\"{0=java.lang.RuntimeException\" + System.lineSeparator() + \"}\").equals(errorMessage);\n        } else {\n            String pattern1 = \"{0=java.lang.RuntimeException\" + System.lineSeparator() + \", 1=java.lang.RuntimeException\" + System.lineSeparator() + \"}\";\n            String pattern2 = \"{1=java.lang.RuntimeException\" + System.lineSeparator() + \", 0=java.lang.RuntimeException\" + System.lineSeparator() + \"}\";\n            return errorMessage.equals(pattern1) || errorMessage.equals(pattern2);\n        }\n    }\n    \n    @Test\n    void assertExecuteSuccessForSingleShardingItems() {\n        assertExecuteSuccess(createSingleShardingContexts());\n    }\n    \n    @Test\n    void assertExecuteSuccessForMultipleShardingItems() {\n        assertExecuteSuccess(createMultipleShardingContexts());\n    }\n    \n    private void assertExecuteSuccess(final ShardingContexts shardingContexts) {\n        prepareForIsNotMisfire(jobFacade, shardingContexts);\n        elasticJobExecutor.execute();\n        verify(jobFacade).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_STAGING, \"Job 'test_job' execute begin.\");\n        verify(jobFacade).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_FINISHED, \"\");\n        verifyForIsNotMisfire(jobFacade, shardingContexts);\n        verify(jobItemExecutor, times(shardingContexts.getShardingTotalCount())).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n    }\n    \n    @Test\n    void assertExecuteWithMisfireIsEmpty() {\n        ShardingContexts shardingContexts = createMultipleShardingContexts();\n        when(jobFacade.getShardingContexts()).thenReturn(shardingContexts);\n        elasticJobExecutor.execute();\n        verifyForIsNotMisfire(jobFacade, shardingContexts);\n        verify(jobItemExecutor, times(2)).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n    }\n    \n    @Test\n    void assertExecuteWithMisfireIsNotEmptyButIsNotEligibleForJobRunning() {\n        ShardingContexts shardingContexts = createMultipleShardingContexts();\n        when(jobFacade.getShardingContexts()).thenReturn(shardingContexts);\n        elasticJobExecutor.execute();\n        verifyForIsNotMisfire(jobFacade, shardingContexts);\n        verify(jobItemExecutor, times(2)).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n        verify(jobFacade, times(0)).clearMisfire(shardingContexts.getShardingItemParameters().keySet());\n    }\n    \n    @Test\n    void assertExecuteWithMisfire() {\n        ShardingContexts shardingContexts = createMultipleShardingContexts();\n        when(jobFacade.getShardingContexts()).thenReturn(shardingContexts);\n        when(jobFacade.isExecuteMisfired(shardingContexts.getShardingItemParameters().keySet())).thenReturn(true, false);\n        elasticJobExecutor.execute();\n        verify(jobFacade).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_STAGING, \"Job 'test_job' execute begin.\");\n        verify(jobFacade, times(2)).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_RUNNING, \"\");\n        verify(jobFacade).misfireIfRunning(shardingContexts.getShardingItemParameters().keySet());\n        verify(jobFacade, times(2)).registerJobBegin(shardingContexts);\n        verify(jobItemExecutor, times(4)).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n        verify(jobFacade, times(2)).registerJobCompleted(shardingContexts);\n    }\n    \n    @Test\n    void assertBeforeJobExecutedFailure() {\n        assertThrows(JobSystemException.class, () -> {\n            ShardingContexts shardingContexts = createMultipleShardingContexts();\n            when(jobFacade.getShardingContexts()).thenReturn(shardingContexts);\n            doThrow(RuntimeException.class).when(jobFacade).beforeJobExecuted(shardingContexts);\n            try {\n                elasticJobExecutor.execute();\n            } finally {\n                verify(jobItemExecutor, times(0)).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n            }\n        });\n    }\n    \n    @Test\n    void assertAfterJobExecutedFailure() {\n        assertThrows(JobSystemException.class, () -> {\n            ShardingContexts shardingContexts = createMultipleShardingContexts();\n            when(jobFacade.getShardingContexts()).thenReturn(shardingContexts);\n            doThrow(RuntimeException.class).when(jobFacade).afterJobExecuted(shardingContexts);\n            try {\n                elasticJobExecutor.execute();\n            } finally {\n                verify(jobItemExecutor, times(2)).process(eq(fooJob), eq(jobConfig), eq(jobRuntimeService), any());\n            }\n        });\n    }\n    \n    private ShardingContexts createSingleShardingContexts() {\n        Map<Integer, String> map = new HashMap<>(1, 1);\n        map.put(0, \"A\");\n        return new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", map);\n    }\n    \n    private ShardingContexts createMultipleShardingContexts() {\n        Map<Integer, String> map = new HashMap<>(2, 1);\n        map.put(0, \"A\");\n        map.put(1, \"B\");\n        return new ShardingContexts(\"fake_task_id\", \"test_job\", 2, \"\", map);\n    }\n    \n    private void prepareForIsNotMisfire(final JobFacade jobFacade, final ShardingContexts shardingContexts) {\n        when(jobFacade.getShardingContexts()).thenReturn(shardingContexts);\n        when(jobFacade.misfireIfRunning(shardingContexts.getShardingItemParameters().keySet())).thenReturn(false);\n        lenient().when(jobFacade.isExecuteMisfired(shardingContexts.getShardingItemParameters().keySet())).thenReturn(false);\n    }\n    \n    private void verifyForIsNotMisfire(final JobFacade jobFacade, final ShardingContexts shardingContexts) {\n        try {\n            verify(jobFacade).checkJobExecutionEnvironment();\n        } catch (final JobExecutionEnvironmentException ex) {\n            throw new RuntimeException(ex);\n        }\n        verify(jobFacade).postJobStatusTraceEvent(shardingContexts.getTaskId(), State.TASK_STAGING, \"Job 'test_job' execute begin.\");\n        verify(jobFacade).beforeJobExecuted(shardingContexts);\n        verify(jobFacade).registerJobBegin(shardingContexts);\n        verify(jobFacade).registerJobCompleted(shardingContexts);\n        verify(jobFacade).afterJobExecuted(shardingContexts);\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/error/handler/JobErrorHandlerReloaderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.error.handler;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.error.handler.fixture.BarJobErrorHandlerFixture;\nimport org.apache.shardingsphere.elasticjob.kernel.executor.error.handler.fixture.FooJobErrorHandlerFixture;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass JobErrorHandlerReloaderTest {\n    \n    @Mock\n    private JobErrorHandler jobErrorHandler;\n    \n    @Test\n    void assertInitialize() {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"job\", 1).jobErrorHandlerType(\"FOO\").build();\n        try (JobErrorHandlerReloader jobErrorHandlerReloader = new JobErrorHandlerReloader(jobConfig)) {\n            JobErrorHandler actual = jobErrorHandlerReloader.getJobErrorHandler();\n            assertNotNull(actual);\n            assertThat(actual.getType(), is(\"FOO\"));\n            assertTrue(actual instanceof FooJobErrorHandlerFixture);\n        }\n    }\n    \n    @Test\n    void assertReload() {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"job\", 1).jobErrorHandlerType(\"FOO\").build();\n        try (JobErrorHandlerReloader jobErrorHandlerReloader = new JobErrorHandlerReloader(jobConfig)) {\n            when(jobErrorHandler.getType()).thenReturn(\"mock\");\n            ReflectionUtils.setFieldValue(jobErrorHandlerReloader, \"jobErrorHandler\", jobErrorHandler);\n            ReflectionUtils.setFieldValue(jobErrorHandlerReloader, \"props\", new Properties());\n            JobConfiguration newJobConfig = JobConfiguration.newBuilder(\"job\", 1).jobErrorHandlerType(\"BAR\").build();\n            jobErrorHandlerReloader.reloadIfNecessary(newJobConfig);\n            verify(jobErrorHandler).close();\n            JobErrorHandler actual = jobErrorHandlerReloader.getJobErrorHandler();\n            assertThat(actual.getType(), is(\"BAR\"));\n            assertTrue(actual instanceof BarJobErrorHandlerFixture);\n        }\n    }\n    \n    @Test\n    void assertUnnecessaryToReload() {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"job\", 1).jobErrorHandlerType(\"FOO\").build();\n        try (JobErrorHandlerReloader jobErrorHandlerReloader = new JobErrorHandlerReloader(jobConfig)) {\n            JobErrorHandler expected = jobErrorHandlerReloader.getJobErrorHandler();\n            jobErrorHandlerReloader.reloadIfNecessary(jobConfig);\n            JobErrorHandler actual = jobErrorHandlerReloader.getJobErrorHandler();\n            assertThat(actual, is(expected));\n        }\n    }\n    \n    @Test\n    void assertShutdown() {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"job\", 1).jobErrorHandlerType(\"FOO\").build();\n        try (JobErrorHandlerReloader jobErrorHandlerReloader = new JobErrorHandlerReloader(jobConfig)) {\n            ReflectionUtils.setFieldValue(jobErrorHandlerReloader, \"jobErrorHandler\", jobErrorHandler);\n            jobErrorHandlerReloader.close();\n            verify(jobErrorHandler).close();\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/error/handler/fixture/BarJobErrorHandlerFixture.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.error.handler.fixture;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\n\npublic final class BarJobErrorHandlerFixture implements JobErrorHandler {\n    \n    @Override\n    public void handleException(final String jobName, final Throwable cause) {\n    }\n    \n    @Override\n    public String getType() {\n        return \"BAR\";\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/error/handler/fixture/FooJobErrorHandlerFixture.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.error.handler.fixture;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler;\n\npublic final class FooJobErrorHandlerFixture implements JobErrorHandler {\n    \n    @Override\n    public void handleException(final String jobName, final Throwable cause) {\n        throw new JobSystemException(cause);\n    }\n    \n    @Override\n    public String getType() {\n        return \"FOO\";\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/facade/ShardingJobFacadeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.facade;\n\nimport com.google.common.collect.Lists;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionEnvironmentException;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionContextService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.fixture.ElasticJobListenerCaller;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.fixture.TestElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.event.JobTracingEventBus;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ShardingJobFacadeTest {\n    \n    @Mock\n    private ConfigurationService configService;\n    \n    @Mock\n    private ShardingService shardingService;\n    \n    @Mock\n    private ExecutionContextService executionContextService;\n    \n    @Mock\n    private ExecutionService executionService;\n    \n    @Mock\n    private FailoverService failoverService;\n    \n    @Mock\n    private JobTracingEventBus jobTracingEventBus;\n    \n    @Mock\n    private ElasticJobListenerCaller caller;\n    \n    private ShardingJobFacade shardingJobFacade;\n    \n    private StringBuilder orderResult;\n    \n    @BeforeEach\n    void setUp() {\n        orderResult = new StringBuilder();\n        shardingJobFacade = new ShardingJobFacade(null, \"test_job\",\n                Arrays.asList(new TestElasticJobListener(caller, \"l1\", 2, orderResult), new TestElasticJobListener(caller, \"l2\", 1, orderResult)), null);\n        ReflectionUtils.setSuperclassFieldValue(shardingJobFacade, \"configService\", configService);\n        ReflectionUtils.setSuperclassFieldValue(shardingJobFacade, \"shardingService\", shardingService);\n        ReflectionUtils.setSuperclassFieldValue(shardingJobFacade, \"executionContextService\", executionContextService);\n        ReflectionUtils.setSuperclassFieldValue(shardingJobFacade, \"executionService\", executionService);\n        ReflectionUtils.setSuperclassFieldValue(shardingJobFacade, \"failoverService\", failoverService);\n        ReflectionUtils.setSuperclassFieldValue(shardingJobFacade, \"jobTracingEventBus\", jobTracingEventBus);\n        ReflectionUtils.setFieldValue(shardingJobFacade, \"configService\", configService);\n        ReflectionUtils.setFieldValue(shardingJobFacade, \"shardingService\", shardingService);\n        ReflectionUtils.setFieldValue(shardingJobFacade, \"executionContextService\", executionContextService);\n        ReflectionUtils.setFieldValue(shardingJobFacade, \"executionService\", executionService);\n        ReflectionUtils.setFieldValue(shardingJobFacade, \"failoverService\", failoverService);\n        ReflectionUtils.setFieldValue(shardingJobFacade, \"jobTracingEventBus\", jobTracingEventBus);\n    }\n    \n    @Test\n    void assertLoad() {\n        JobConfiguration expected = JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build();\n        when(configService.load(true)).thenReturn(expected);\n        assertThat(shardingJobFacade.loadJobConfiguration(true), is(expected));\n    }\n    \n    @Test\n    void assertCheckMaxTimeDiffSecondsTolerable() throws JobExecutionEnvironmentException {\n        shardingJobFacade.checkJobExecutionEnvironment();\n        verify(configService).checkMaxTimeDiffSecondsTolerable();\n    }\n    \n    @Test\n    void assertFailoverIfUnnecessary() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(false).build());\n        shardingJobFacade.failoverIfNecessary();\n        verify(failoverService, times(0)).failoverIfNecessary();\n    }\n    \n    @Test\n    void assertFailoverIfNecessary() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).monitorExecution(true).build());\n        shardingJobFacade.failoverIfNecessary();\n        verify(failoverService).failoverIfNecessary();\n    }\n    \n    @Test\n    void assertRegisterJobBegin() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", Collections.emptyMap());\n        shardingJobFacade.registerJobBegin(shardingContexts);\n        verify(executionService).registerJobBegin(shardingContexts);\n    }\n    \n    @Test\n    void assertRegisterJobCompletedWhenFailoverDisabled() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(false).build());\n        shardingJobFacade.registerJobCompleted(shardingContexts);\n        verify(executionService).registerJobCompleted(shardingContexts);\n        verify(failoverService, times(0)).updateFailoverComplete(shardingContexts.getShardingItemParameters().keySet());\n    }\n    \n    @Test\n    void assertRegisterJobCompletedWhenFailoverEnabled() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).monitorExecution(true).build());\n        shardingJobFacade.registerJobCompleted(shardingContexts);\n        verify(executionService).registerJobCompleted(shardingContexts);\n        verify(failoverService).updateFailoverComplete(shardingContexts.getShardingItemParameters().keySet());\n    }\n    \n    @Test\n    void assertGetShardingContextWhenIsFailoverEnableAndFailover() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).monitorExecution(true).build());\n        when(failoverService.getLocalFailoverItems()).thenReturn(Collections.singletonList(1));\n        when(executionContextService.getJobShardingContext(Collections.singletonList(1))).thenReturn(shardingContexts);\n        assertThat(shardingJobFacade.getShardingContexts(), is(shardingContexts));\n        verify(shardingService, times(0)).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertGetShardingContextWhenIsFailoverEnableAndNotFailover() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).monitorExecution(true).build());\n        when(failoverService.getLocalFailoverItems()).thenReturn(Collections.emptyList());\n        when(shardingService.getLocalShardingItems()).thenReturn(Lists.newArrayList(0, 1));\n        when(failoverService.getLocalTakeOffItems()).thenReturn(Collections.singletonList(0));\n        when(executionContextService.getJobShardingContext(Collections.singletonList(1))).thenReturn(shardingContexts);\n        assertThat(shardingJobFacade.getShardingContexts(), is(shardingContexts));\n        verify(shardingService).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertGetShardingContextWhenIsFailoverDisable() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(false).build());\n        when(shardingService.getLocalShardingItems()).thenReturn(Arrays.asList(0, 1));\n        when(executionContextService.getJobShardingContext(Arrays.asList(0, 1))).thenReturn(shardingContexts);\n        assertThat(shardingJobFacade.getShardingContexts(), is(shardingContexts));\n        verify(shardingService).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertGetShardingContextWhenHasDisabledItems() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(false).build());\n        when(shardingService.getLocalShardingItems()).thenReturn(Lists.newArrayList(0, 1));\n        when(executionService.getDisabledItems(Arrays.asList(0, 1))).thenReturn(Collections.singletonList(1));\n        when(executionContextService.getJobShardingContext(Collections.singletonList(0))).thenReturn(shardingContexts);\n        assertThat(shardingJobFacade.getShardingContexts(), is(shardingContexts));\n        verify(shardingService).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertMisfireIfRunning() {\n        when(executionService.misfireIfHasRunningItems(Arrays.asList(0, 1))).thenReturn(true);\n        assertThat(shardingJobFacade.misfireIfRunning(Arrays.asList(0, 1)), is(true));\n    }\n    \n    @Test\n    void assertClearMisfire() {\n        shardingJobFacade.clearMisfire(Arrays.asList(0, 1));\n        verify(executionService).clearMisfire(Arrays.asList(0, 1));\n    }\n    \n    @Test\n    void assertIsNeedSharding() {\n        when(shardingService.isNeedSharding()).thenReturn(true);\n        assertThat(shardingJobFacade.isNeedSharding(), is(true));\n    }\n    \n    @Test\n    void assertBeforeJobExecuted() {\n        shardingJobFacade.beforeJobExecuted(new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", Collections.emptyMap()));\n        verify(caller, times(2)).before();\n        assertThat(orderResult.toString(), is(\"l2l1\"));\n    }\n    \n    @Test\n    void assertAfterJobExecuted() {\n        shardingJobFacade.afterJobExecuted(new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", Collections.emptyMap()));\n        verify(caller, times(2)).after();\n        assertThat(orderResult.toString(), is(\"l2l1\"));\n    }\n    \n    @Test\n    void assertPostJobExecutionEvent() {\n        shardingJobFacade.postJobExecutionEvent(null);\n        verify(jobTracingEventBus).post(null);\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/facade/SingleShardingJobFacadeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.facade;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport com.google.common.collect.Lists;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionEnvironmentException;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionContextService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.fixture.ElasticJobListenerCaller;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.fixture.TestElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.event.JobTracingEventBus;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\n@ExtendWith(MockitoExtension.class)\nclass SingleShardingJobFacadeTest {\n    \n    @Mock\n    private ConfigurationService configService;\n    \n    @Mock\n    private ShardingService shardingService;\n    \n    @Mock\n    private ExecutionContextService executionContextService;\n    \n    @Mock\n    private ExecutionService executionService;\n    \n    @Mock\n    private FailoverService failoverService;\n    \n    @Mock\n    private JobTracingEventBus jobTracingEventBus;\n    \n    @Mock\n    private ElasticJobListenerCaller caller;\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private InstanceService instanceService;\n    \n    private SingleShardingJobFacade singleShardingJobFacade;\n    \n    private StringBuilder orderResult;\n    \n    @BeforeEach\n    void setUp() {\n        orderResult = new StringBuilder();\n        singleShardingJobFacade = new SingleShardingJobFacade(null, \"test_job\",\n                Arrays.asList(new TestElasticJobListener(caller, \"l1\", 2, orderResult), new TestElasticJobListener(caller, \"l2\", 1, orderResult)), null);\n        ReflectionUtils.setSuperclassFieldValue(singleShardingJobFacade, \"configService\", configService);\n        ReflectionUtils.setSuperclassFieldValue(singleShardingJobFacade, \"shardingService\", shardingService);\n        ReflectionUtils.setSuperclassFieldValue(singleShardingJobFacade, \"executionContextService\", executionContextService);\n        ReflectionUtils.setSuperclassFieldValue(singleShardingJobFacade, \"executionService\", executionService);\n        ReflectionUtils.setSuperclassFieldValue(singleShardingJobFacade, \"failoverService\", failoverService);\n        ReflectionUtils.setSuperclassFieldValue(singleShardingJobFacade, \"jobTracingEventBus\", jobTracingEventBus);\n        ReflectionUtils.setFieldValue(singleShardingJobFacade, \"configService\", configService);\n        ReflectionUtils.setFieldValue(singleShardingJobFacade, \"shardingService\", shardingService);\n        ReflectionUtils.setFieldValue(singleShardingJobFacade, \"executionContextService\", executionContextService);\n        ReflectionUtils.setFieldValue(singleShardingJobFacade, \"executionService\", executionService);\n        ReflectionUtils.setFieldValue(singleShardingJobFacade, \"failoverService\", failoverService);\n        ReflectionUtils.setFieldValue(singleShardingJobFacade, \"jobTracingEventBus\", jobTracingEventBus);\n        ReflectionUtils.setFieldValue(singleShardingJobFacade, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(singleShardingJobFacade, \"instanceService\", instanceService);\n    }\n    \n    @Test\n    void assertLoad() {\n        JobConfiguration expected = JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").build();\n        when(configService.load(true)).thenReturn(expected);\n        assertThat(singleShardingJobFacade.loadJobConfiguration(true), is(expected));\n    }\n    \n    @Test\n    void assertCheckMaxTimeDiffSecondsTolerable() throws JobExecutionEnvironmentException {\n        singleShardingJobFacade.checkJobExecutionEnvironment();\n        verify(configService).checkMaxTimeDiffSecondsTolerable();\n    }\n    \n    @Test\n    void assertFailoverIfUnnecessary() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(false).build());\n        singleShardingJobFacade.failoverIfNecessary();\n        verify(failoverService, times(0)).failoverIfNecessary();\n    }\n    \n    @Test\n    void assertFailoverIfNecessary() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(true).monitorExecution(true).build());\n        singleShardingJobFacade.failoverIfNecessary();\n        verify(failoverService).failoverIfNecessary();\n    }\n    \n    @Test\n    void assertRegisterJobBegin() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        singleShardingJobFacade.registerJobBegin(shardingContexts);\n        verify(executionService).registerJobBegin(shardingContexts);\n    }\n    \n    @Test\n    void assertRegisterJobCompletedWhenFailoverDisabled() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(false).build());\n        singleShardingJobFacade.registerJobCompleted(shardingContexts);\n        verify(executionService).registerJobCompleted(shardingContexts);\n        verify(failoverService, times(0)).updateFailoverComplete(shardingContexts.getShardingItemParameters().keySet());\n    }\n    \n    @Test\n    void assertRegisterJobCompletedWhenFailoverEnabled() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(true).monitorExecution(true).build());\n        singleShardingJobFacade.registerJobCompleted(shardingContexts);\n        verify(executionService).registerJobCompleted(shardingContexts);\n        verify(failoverService).updateFailoverComplete(shardingContexts.getShardingItemParameters().keySet());\n    }\n    \n    @Test\n    void assertRegisterJobCompletedWhenRunningOnCurrentHost() {\n        final ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(true).monitorExecution(true).build());\n        JobInstance jobInstance = new JobInstance();\n        jobInstance.setServerIp(\"192.168.1.2\");\n        JobRegistry jobRegistry = JobRegistry.getInstance();\n        jobRegistry.addJobInstance(\"test_job\", jobInstance);\n        List<JobInstance> availJobInst = new ArrayList<>();\n        availJobInst.add(jobInstance);\n        JobInstance jobInstance2 = new JobInstance();\n        jobInstance2.setServerIp(\"192.168.1.3\");\n        availJobInst.add(jobInstance2);\n        when(instanceService.getAvailableJobInstances()).thenReturn(availJobInst);\n        \n        singleShardingJobFacade.registerJobCompleted(shardingContexts);\n        \n        verify(executionService).registerJobCompleted(shardingContexts);\n        verify(failoverService).updateFailoverComplete(shardingContexts.getShardingItemParameters().keySet());\n        verify(jobNodeStorage).fillEphemeralJobNode(\"next-job-instance-ip\", availJobInst.get(1).getServerIp());\n    }\n    \n    @Test\n    void assertRegisterJobCompletedWhenRunningOnOtherHost() {\n        final ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(true).monitorExecution(true).build());\n        JobInstance jobInstance = new JobInstance();\n        jobInstance.setServerIp(\"192.168.1.2\");\n        JobRegistry jobRegistry = JobRegistry.getInstance();\n        jobRegistry.addJobInstance(\"test_job\", jobInstance);\n        List<JobInstance> availJobInst = new ArrayList<>();\n        JobInstance jobInstance2 = new JobInstance();\n        jobInstance2.setServerIp(\"192.168.1.3\");\n        availJobInst.add(jobInstance2);\n        when(instanceService.getAvailableJobInstances()).thenReturn(availJobInst);\n        \n        singleShardingJobFacade.registerJobCompleted(shardingContexts);\n        \n        verify(executionService).registerJobCompleted(shardingContexts);\n        verify(failoverService).updateFailoverComplete(shardingContexts.getShardingItemParameters().keySet());\n        verify(jobNodeStorage, times(0)).fillEphemeralJobNode(\"next-job-instance-ip\", availJobInst.get(0).getServerIp());\n    }\n    \n    @Test\n    void assertGetShardingContextWhenIsFailoverEnableAndFailover() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(true).monitorExecution(true).build());\n        when(failoverService.getLocalFailoverItems()).thenReturn(Collections.singletonList(0));\n        when(executionContextService.getJobShardingContext(Collections.singletonList(0))).thenReturn(shardingContexts);\n        assertThat(singleShardingJobFacade.getShardingContexts(), is(shardingContexts));\n        verify(shardingService, times(0)).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertGetShardingContextWhenIsFailoverEnableAndNotFailover() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(true).monitorExecution(true).build());\n        when(failoverService.getLocalFailoverItems()).thenReturn(Collections.emptyList());\n        when(shardingService.getLocalShardingItems()).thenReturn(Lists.newArrayList(0));\n        when(failoverService.getLocalTakeOffItems()).thenReturn(Collections.emptyList());\n        when(executionContextService.getJobShardingContext(Collections.singletonList(0))).thenReturn(shardingContexts);\n        assertThat(singleShardingJobFacade.getShardingContexts(), is(shardingContexts));\n        verify(shardingService).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertGetShardingContextWhenIsFailoverDisable() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(false).build());\n        when(shardingService.getLocalShardingItems()).thenReturn(Collections.singletonList(0));\n        when(executionContextService.getJobShardingContext(Collections.singletonList(0))).thenReturn(shardingContexts);\n        assertThat(singleShardingJobFacade.getShardingContexts(), is(shardingContexts));\n        verify(shardingService).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertGetShardingContextWhenHasDisabledItems() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(false).build());\n        when(shardingService.getLocalShardingItems()).thenReturn(Lists.newArrayList(0));\n        when(executionService.getDisabledItems(Collections.singletonList(0))).thenReturn(Collections.singletonList(0));\n        when(executionContextService.getJobShardingContext(Collections.emptyList())).thenReturn(shardingContexts);\n        assertThat(singleShardingJobFacade.getShardingContexts(), is(shardingContexts));\n        verify(shardingService).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertGetShardingContextWhenIsFailoverDisableAndNoNeedShardingWithoutNextIP() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(false).build());\n        when(shardingService.isNeedSharding()).thenReturn(false);\n        when(jobNodeStorage.getJobNodeDataDirectly(\"next-job-instance-ip\")).thenReturn(null);\n        when(shardingService.getLocalShardingItems()).thenReturn(Collections.singletonList(0));\n        when(executionContextService.getJobShardingContext(Collections.singletonList(0))).thenReturn(shardingContexts);\n        \n        assertThat(singleShardingJobFacade.getShardingContexts(), is(shardingContexts));\n        \n        verify(shardingService, times(1)).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertGetShardingContextWhenIsFailoverDisableAndNoNeedShardingWithNextIP() {\n        final ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(false).build());\n        when(shardingService.isNeedSharding()).thenReturn(false);\n        when(jobNodeStorage.getJobNodeDataDirectly(\"next-job-instance-ip\")).thenReturn(\"192.168.1.2\");\n        JobInstance jobInstance = new JobInstance();\n        jobInstance.setServerIp(\"192.168.1.2\");\n        JobRegistry jobRegistry = JobRegistry.getInstance();\n        jobRegistry.addJobInstance(\"test_job\", jobInstance);\n        when(executionContextService.getJobShardingContext(Collections.singletonList(0))).thenReturn(shardingContexts);\n        \n        assertThat(singleShardingJobFacade.getShardingContexts(), is(shardingContexts));\n        \n        verify(shardingService, times(0)).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertGetShardingContextWhenIsFailoverDisableAndNeedSharding() {\n        ShardingContexts shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap());\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).cron(\"0/1 * * * * ?\").failover(false).build());\n        when(shardingService.getLocalShardingItems()).thenReturn(Collections.singletonList(0));\n        when(shardingService.isNeedSharding()).thenReturn(true);\n        when(executionContextService.getJobShardingContext(Collections.singletonList(0))).thenReturn(shardingContexts);\n        \n        assertThat(singleShardingJobFacade.getShardingContexts(), is(shardingContexts));\n        \n        verify(shardingService).shardingIfNecessary();\n    }\n    \n    @Test\n    void assertMisfireIfRunning() {\n        when(executionService.misfireIfHasRunningItems(Arrays.asList(0, 1))).thenReturn(true);\n        assertThat(singleShardingJobFacade.misfireIfRunning(Arrays.asList(0, 1)), is(true));\n    }\n    \n    @Test\n    void assertClearMisfire() {\n        singleShardingJobFacade.clearMisfire(Arrays.asList(0, 1));\n        verify(executionService).clearMisfire(Arrays.asList(0, 1));\n    }\n    \n    @Test\n    void assertIsNeedSharding() {\n        when(shardingService.isNeedSharding()).thenReturn(true);\n        assertThat(singleShardingJobFacade.isNeedSharding(), is(true));\n    }\n    \n    @Test\n    void assertBeforeJobExecuted() {\n        singleShardingJobFacade.beforeJobExecuted(new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap()));\n        verify(caller, times(2)).before();\n        assertThat(orderResult.toString(), is(\"l2l1\"));\n    }\n    \n    @Test\n    void assertAfterJobExecuted() {\n        singleShardingJobFacade.afterJobExecuted(new ShardingContexts(\"fake_task_id\", \"test_job\", 1, \"\", Collections.emptyMap()));\n        verify(caller, times(2)).after();\n        assertThat(orderResult.toString(), is(\"l2l1\"));\n    }\n    \n    @Test\n    void assertPostJobExecutionEvent() {\n        singleShardingJobFacade.postJobExecutionEvent(null);\n        verify(jobTracingEventBus).post(null);\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/item/JobItemExecutorFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.item;\n\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.executor.ClassedFooJobExecutor;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.job.DetailedFooJob;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.job.FailedJob;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.job.FooJob;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.instanceOf;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass JobItemExecutorFactoryTest {\n    \n    @Test\n    void assertGetExecutorByClassFailureWithInvalidType() {\n        assertThrows(JobConfigurationException.class, () -> JobItemExecutorFactory.getExecutor(FailedJob.class));\n    }\n    \n    @Test\n    void assertGetExecutorByClassSuccessWithCurrentClass() {\n        assertThat(JobItemExecutorFactory.getExecutor(FooJob.class), instanceOf(ClassedFooJobExecutor.class));\n    }\n    \n    @Test\n    void assertGetExecutorByClassSuccessWithSubClass() {\n        assertThat(JobItemExecutorFactory.getExecutor(DetailedFooJob.class), instanceOf(ClassedFooJobExecutor.class));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/threadpool/ElasticJobExecutorServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.threadpool;\n\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ElasticJobExecutorServiceTest {\n    \n    private static boolean hasExecuted;\n    \n    @Test\n    void assertCreateExecutorService() {\n        ElasticJobExecutorService executorServiceObject = new ElasticJobExecutorService(\"executor-service-test\", 1);\n        assertThat(executorServiceObject.getActiveThreadCount(), is(0));\n        assertThat(executorServiceObject.getWorkQueueSize(), is(0));\n        assertFalse(executorServiceObject.isShutdown());\n        ExecutorService executorService = executorServiceObject.createExecutorService();\n        executorService.submit(new FooTask());\n        Awaitility.await().atLeast(1L, TimeUnit.MILLISECONDS).atMost(5L, TimeUnit.MINUTES).untilAsserted(() -> {\n            assertThat(executorServiceObject.getActiveThreadCount(), is(1));\n            assertThat(executorServiceObject.getWorkQueueSize(), is(0));\n            assertFalse(executorServiceObject.isShutdown());\n        });\n        executorService.submit(new FooTask());\n        Awaitility.await().atLeast(1L, TimeUnit.MILLISECONDS).atMost(5L, TimeUnit.MINUTES).untilAsserted(() -> {\n            assertThat(executorServiceObject.getActiveThreadCount(), is(1));\n            assertThat(executorServiceObject.getWorkQueueSize(), is(1));\n            assertFalse(executorServiceObject.isShutdown());\n        });\n        executorService.shutdownNow();\n        assertThat(executorServiceObject.getWorkQueueSize(), is(0));\n        assertTrue(executorServiceObject.isShutdown());\n        hasExecuted = true;\n    }\n    \n    static class FooTask implements Runnable {\n        \n        @Override\n        public void run() {\n            Awaitility.await().atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> assertThat(hasExecuted, is(true)));\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/threadpool/ExecutorServiceReloaderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.threadpool;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.concurrent.ExecutorService;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass ExecutorServiceReloaderTest {\n    \n    @Mock\n    private ExecutorService mockExecutorService;\n    \n    @Test\n    void assertInitialize() {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"job\", 1).jobExecutorThreadPoolSizeProviderType(\"SINGLE_THREAD\").build();\n        try (ExecutorServiceReloader executorServiceReloader = new ExecutorServiceReloader(jobConfig)) {\n            ExecutorService actual = executorServiceReloader.getExecutorService();\n            assertNotNull(actual);\n            assertFalse(actual.isShutdown());\n            assertFalse(actual.isTerminated());\n            actual.shutdown();\n        }\n    }\n    \n    @Test\n    void assertReload() {\n        ExecutorServiceReloader executorServiceReloader = new ExecutorServiceReloader(JobConfiguration.newBuilder(\"job\", 1).jobExecutorThreadPoolSizeProviderType(\"SINGLE_THREAD\").build());\n        ReflectionUtils.setFieldValue(executorServiceReloader, \"jobExecutorThreadPoolSizeProviderType\", \"mock\");\n        ReflectionUtils.setFieldValue(executorServiceReloader, \"executorService\", mockExecutorService);\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"job\", 1).build();\n        executorServiceReloader.reloadIfNecessary(jobConfig);\n        verify(mockExecutorService).shutdownNow();\n        ExecutorService actual = executorServiceReloader.getExecutorService();\n        assertFalse(actual.isShutdown());\n        assertFalse(actual.isTerminated());\n        actual.shutdown();\n    }\n    \n    @Test\n    void assertUnnecessaryToReload() {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"job\", 1).jobExecutorThreadPoolSizeProviderType(\"CPU\").build();\n        try (ExecutorServiceReloader executorServiceReloader = new ExecutorServiceReloader(jobConfig)) {\n            ExecutorService expected = executorServiceReloader.getExecutorService();\n            executorServiceReloader.reloadIfNecessary(jobConfig);\n            ExecutorService actual = executorServiceReloader.getExecutorService();\n            assertThat(actual, is(expected));\n            actual.shutdown();\n        }\n    }\n    \n    @Test\n    void assertShutdown() {\n        ExecutorServiceReloader executorServiceReloader = new ExecutorServiceReloader(JobConfiguration.newBuilder(\"job\", 1).jobExecutorThreadPoolSizeProviderType(\"SINGLE_THREAD\").build());\n        ReflectionUtils.setFieldValue(executorServiceReloader, \"executorService\", mockExecutorService);\n        executorServiceReloader.close();\n        verify(mockExecutorService).shutdownNow();\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/threadpool/type/CPUUsageJobExecutorThreadPoolSizeProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.threadpool.type;\n\nimport org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.JobExecutorThreadPoolSizeProvider;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass CPUUsageJobExecutorThreadPoolSizeProviderTest {\n    \n    @Test\n    void assertGetPoolSize() {\n        assertThat((TypedSPILoader.getService(JobExecutorThreadPoolSizeProvider.class, \"CPU\")).getSize(), is(Runtime.getRuntime().availableProcessors() * 2));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/executor/threadpool/type/SingleThreadJobExecutorThreadPoolSizeProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.executor.threadpool.type;\n\nimport org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.JobExecutorThreadPoolSizeProvider;\nimport org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass SingleThreadJobExecutorThreadPoolSizeProviderTest {\n    \n    @Test\n    void assertGetPoolSize() {\n        assertThat((TypedSPILoader.getService(JobExecutorThreadPoolSizeProvider.class, \"SINGLE_THREAD\")).getSize(), is(1));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/fixture/YamlConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.fixture;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class YamlConstants {\n    \n    private static final String JOB_YAML = \"jobName: test_job\\n\"\n            + \"cron: 0/1 * * * * ?\\n\"\n            + \"shardingTotalCount: 3\\n\"\n            + \"jobParameter: 'param'\\n\"\n            + \"failover: %s\\n\"\n            + \"monitorExecution: %s\\n\"\n            + \"misfire: false\\n\"\n            + \"maxTimeDiffSeconds: %s\\n\"\n            + \"reconcileIntervalMinutes: 15\\n\"\n            + \"description: 'desc'\\n\"\n            + \"disabled: true\\n\"\n            + \"overwrite: true\";\n    \n    private static final boolean DEFAULT_FAILOVER = true;\n    \n    private static final boolean DEFAULT_MONITOR_EXECUTION = true;\n    \n    private static final int DEFAULT_MAX_TIME_DIFF_SECONDS = 1000;\n    \n    /**\n     * Get the config of simple job in YAML format.\n     *\n     * @return the string of job config\n     */\n    public static String getJobYaml() {\n        return String.format(JOB_YAML, DEFAULT_FAILOVER, DEFAULT_MONITOR_EXECUTION, DEFAULT_MAX_TIME_DIFF_SECONDS);\n    }\n    \n    /**\n     * Get the config of simple job in YAML format.\n     *\n     * @param maxTimeDiffSeconds max different time in seconds\n     * @return the string of job config\n     */\n    public static String getJobYaml(final int maxTimeDiffSeconds) {\n        return String.format(JOB_YAML, DEFAULT_FAILOVER, DEFAULT_MONITOR_EXECUTION, maxTimeDiffSeconds);\n    }\n    \n    /**\n     * Get the config of simple job in YAML format.\n     *\n     * @param failover Whether to enable failover\n     * @return the string of job config\n     */\n    public static String getJobYamlWithFailover(final boolean failover) {\n        return String.format(JOB_YAML, failover, DEFAULT_MONITOR_EXECUTION, DEFAULT_MAX_TIME_DIFF_SECONDS);\n    }\n    \n    /**\n     * Get the config of simple job in YAML format.\n     *\n     * @param monitorExecution Whether to enable monitor execution\n     * @return the string of job config\n     */\n    public static String getJobYamlWithMonitorExecution(final boolean monitorExecution) {\n        return String.format(JOB_YAML, DEFAULT_FAILOVER, monitorExecution, DEFAULT_MAX_TIME_DIFF_SECONDS);\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/fixture/executor/ClassedFooJobExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.fixture.executor;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.job.FooJob;\n\npublic final class ClassedFooJobExecutor implements ClassedJobItemExecutor<FooJob> {\n    \n    @Override\n    public void process(final FooJob elasticJob, final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService, final ShardingContext shardingContext) {\n        elasticJob.foo(shardingContext);\n    }\n    \n    @Override\n    public Class<FooJob> getElasticJobClass() {\n        return FooJob.class;\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/fixture/executor/TypedFooJobExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.fixture.executor;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.TypedJobItemExecutor;\n\npublic final class TypedFooJobExecutor implements TypedJobItemExecutor {\n    \n    @Override\n    public void process(final ElasticJob elasticJob, final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService, final ShardingContext shardingContext) {\n    }\n    \n    @Override\n    public String getType() {\n        return \"FOO\";\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/fixture/job/DetailedFooJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.fixture.job;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\nimport java.util.Collection;\nimport java.util.concurrent.CopyOnWriteArraySet;\n\npublic final class DetailedFooJob implements FooJob {\n    \n    private final Collection<Integer> completedJobItems = new CopyOnWriteArraySet<>();\n    \n    @Getter\n    private volatile boolean completed;\n    \n    @Override\n    public void foo(final ShardingContext shardingContext) {\n        completedJobItems.add(shardingContext.getShardingItem());\n        completed = completedJobItems.size() == shardingContext.getShardingTotalCount();\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/fixture/job/FailedJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.fixture.job;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\n\npublic final class FailedJob implements ElasticJob {\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/fixture/job/FooJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.fixture.job;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\npublic interface FooJob extends ElasticJob {\n    \n    /**\n     * Do job.\n     *\n     * @param shardingContext sharding context\n     */\n    void foo(ShardingContext shardingContext);\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/env/HostExceptionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.env;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.io.IOException;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass HostExceptionTest {\n    \n    @Test\n    void assertGetCause() {\n        IOException cause = new IOException();\n        assertThat(new HostException(cause).getCause(), is(cause));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/env/IpUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.env;\n\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.Test;\n\nimport java.io.IOException;\nimport java.lang.reflect.Method;\nimport java.net.Inet4Address;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Vector;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nclass IpUtilsTest {\n    \n    @Test\n    void assertGetIp() {\n        assertNotNull(IpUtils.getIp());\n    }\n    \n    @Test\n    void assertPreferredNetworkInterface() throws ReflectiveOperationException {\n        System.setProperty(IpUtils.PREFERRED_NETWORK_INTERFACE, \"eth0\");\n        Method declaredMethod = IpUtils.class.getDeclaredMethod(\"isPreferredNetworkInterface\", NetworkInterface.class);\n        declaredMethod.setAccessible(true);\n        NetworkInterface mockNetworkInterface = mock(NetworkInterface.class);\n        when(mockNetworkInterface.getDisplayName()).thenReturn(\"eth0\");\n        boolean result = (boolean) declaredMethod.invoke(\"isPreferredNetworkInterface\", mockNetworkInterface);\n        assertTrue(result);\n        System.clearProperty(IpUtils.PREFERRED_NETWORK_INTERFACE);\n    }\n    \n    @Test\n    void assertPreferredNetworkAddress() throws ReflectiveOperationException {\n        Method declaredMethod = IpUtils.class.getDeclaredMethod(\"isPreferredAddress\", InetAddress.class);\n        declaredMethod.setAccessible(true);\n        InetAddress inetAddress = mock(InetAddress.class);\n        System.setProperty(IpUtils.PREFERRED_NETWORK_IP, \"192.168\");\n        when(inetAddress.getHostAddress()).thenReturn(\"192.168.0.100\");\n        assertTrue((boolean) declaredMethod.invoke(\"isPreferredAddress\", inetAddress));\n        when(inetAddress.getHostAddress()).thenReturn(\"10.10.0.100\");\n        assertFalse((boolean) declaredMethod.invoke(\"isPreferredAddress\", inetAddress));\n        System.clearProperty(IpUtils.PREFERRED_NETWORK_IP);\n        System.setProperty(IpUtils.PREFERRED_NETWORK_IP, \"10.10.*\");\n        when(inetAddress.getHostAddress()).thenReturn(\"10.10.0.100\");\n        assertTrue((boolean) declaredMethod.invoke(\"isPreferredAddress\", inetAddress));\n        when(inetAddress.getHostAddress()).thenReturn(\"10.0.0.100\");\n        assertFalse((boolean) declaredMethod.invoke(\"isPreferredAddress\", inetAddress));\n        System.clearProperty(IpUtils.PREFERRED_NETWORK_IP);\n    }\n    \n    @Test\n    void assertGetFirstNetworkInterface() throws IOException, ReflectiveOperationException {\n        InetAddress address1 = mock(Inet4Address.class);\n        when(address1.isLoopbackAddress()).thenReturn(false);\n        when(address1.isAnyLocalAddress()).thenReturn(false);\n        when(address1.isReachable(100)).thenReturn(true);\n        when(address1.getHostAddress()).thenReturn(\"10.10.0.1\");\n        Vector<InetAddress> addresses1 = new Vector<>();\n        addresses1.add(address1);\n        InetAddress address2 = mock(Inet4Address.class);\n        when(address2.isLoopbackAddress()).thenReturn(false);\n        when(address2.isAnyLocalAddress()).thenReturn(false);\n        when(address2.isReachable(100)).thenReturn(true);\n        when(address2.getHostAddress()).thenReturn(\"192.168.99.100\");\n        Vector<InetAddress> addresses2 = new Vector<>();\n        addresses2.add(address2);\n        NetworkInterface networkInterface1 = mock(NetworkInterface.class);\n        NetworkInterface networkInterface2 = mock(NetworkInterface.class);\n        when(networkInterface1.getInetAddresses()).thenReturn(addresses1.elements());\n        when(networkInterface2.getInetAddresses()).thenReturn(addresses2.elements());\n        when(networkInterface1.getDisplayName()).thenReturn(\"eth1\");\n        when(networkInterface2.getDisplayName()).thenReturn(\"eth2\");\n        Method declaredMethod = IpUtils.class.getDeclaredMethod(\"getFirstNetworkInterface\", List.class);\n        declaredMethod.setAccessible(true);\n        List<NetworkInterface> validNetworkInterfaces = Arrays.asList(networkInterface1, networkInterface2);\n        assertThat(declaredMethod.invoke(\"getFirstNetworkInterface\", validNetworkInterfaces), is(networkInterface2));\n        System.setProperty(IpUtils.PREFERRED_NETWORK_INTERFACE, \"eth1\");\n        assertThat(declaredMethod.invoke(\"getFirstNetworkInterface\", validNetworkInterfaces), is(networkInterface1));\n        System.clearProperty(IpUtils.PREFERRED_NETWORK_INTERFACE);\n        System.setProperty(IpUtils.PREFERRED_NETWORK_IP, \"10.10.*\");\n        assertThat(declaredMethod.invoke(\"getFirstNetworkInterface\", validNetworkInterfaces), is(networkInterface1));\n        System.clearProperty(IpUtils.PREFERRED_NETWORK_IP);\n    }\n    \n    @Test\n    void assertGetHostName() {\n        assertNotNull(IpUtils.getHostName());\n        assertThat(ReflectionUtils.getStaticFieldValue(IpUtils.class, \"cachedHostName\"), is(IpUtils.getHostName()));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/ExceptionUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ExceptionUtilsTest {\n    \n    @Test\n    void assertTransformWithError() {\n        assertTrue(ExceptionUtils.transform(new Error(\"Error\")).startsWith(\"java.lang.Error\"));\n    }\n    \n    @Test\n    void assertTransformWithException() {\n        assertTrue(ExceptionUtils.transform(new Exception(\"Exception\")).startsWith(\"java.lang.Exception\"));\n    }\n    \n    @Test\n    void assertTransformWithNull() {\n        assertThat(ExceptionUtils.transform(null), is(\"\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/JobConfigurationExceptionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.instanceOf;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass JobConfigurationExceptionTest {\n    \n    @Test\n    void assertGetMessage() {\n        assertThat(new JobConfigurationException(\"message is: '%s'\", \"test\").getMessage(), is(\"message is: 'test'\"));\n    }\n    \n    @Test\n    void assertGetCause() {\n        assertThat(new JobConfigurationException(new RuntimeException()).getCause(), instanceOf(RuntimeException.class));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/JobExecutionEnvironmentExceptionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass JobExecutionEnvironmentExceptionTest {\n    \n    @Test\n    void assertGetMessage() {\n        assertThat(new JobExecutionEnvironmentException(\"message is: '%s'\", \"test\").getMessage(), is(\"message is: 'test'\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/JobSystemExceptionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.instanceOf;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass JobSystemExceptionTest {\n    \n    @Test\n    void assertGetMessage() {\n        assertThat(new JobSystemException(\"message is: '%s'\", \"test\").getMessage(), is(\"message is: 'test'\"));\n    }\n    \n    @Test\n    void assertGetMessageCause() {\n        JobSystemException jobSystemException = new JobSystemException(\"message is: \", new RuntimeException());\n        assertThat(jobSystemException.getMessage(), is(\"message is: \"));\n        assertThat(jobSystemException.getCause(), instanceOf(RuntimeException.class));\n    }\n    \n    @Test\n    void assertGetCause() {\n        assertThat(new JobSystemException(new RuntimeException()).getCause(), instanceOf(RuntimeException.class));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/exception/PropertiesPreconditionsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.exception;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Properties;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass PropertiesPreconditionsTest {\n    \n    @Test\n    void assertValidateIsRequiredWithValidateError() {\n        try {\n            PropertiesPreconditions.checkRequired(new Properties(), \"key\");\n        } catch (IllegalArgumentException ex) {\n            assertThat(ex.getMessage(), is(String.format(\"The property `%s` is required.\", \"key\")));\n        }\n    }\n    \n    @Test\n    void assertValidateIsRequiredWithNormal() {\n        Properties props = new Properties();\n        props.setProperty(\"key\", \"value\");\n        PropertiesPreconditions.checkRequired(props, \"key\");\n    }\n    \n    @Test\n    void assertValidateIsPositiveIntegerWithValueNoExist() {\n        PropertiesPreconditions.checkPositiveInteger(new Properties(), \"key\");\n    }\n    \n    @Test\n    void assertValidateIsPositiveIntegerWithNormal() {\n        Properties props = new Properties();\n        props.setProperty(\"key\", \"1\");\n        PropertiesPreconditions.checkPositiveInteger(props, \"key\");\n    }\n    \n    @Test\n    void assertValidateIsPositiveIntegerWithWrongString() {\n        Properties props = new Properties();\n        props.setProperty(\"key\", \"wrong_value\");\n        try {\n            PropertiesPreconditions.checkPositiveInteger(props, \"key\");\n        } catch (IllegalArgumentException ex) {\n            assertThat(ex.getMessage(), is(String.format(\"The property `%s` should be integer.\", \"key\")));\n        }\n    }\n    \n    @Test\n    void assertValidateIsPositiveIntegerWithNegativeNumber() {\n        Properties props = new Properties();\n        props.setProperty(\"key\", \"-1\");\n        try {\n            PropertiesPreconditions.checkPositiveInteger(props, \"key\");\n        } catch (IllegalArgumentException ex) {\n            assertThat(ex.getMessage(), is(String.format(\"The property `%s` should be positive.\", \"key\")));\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/json/GsonFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.json;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass GsonFactoryTest {\n    \n    @Test\n    void assertGetGson() {\n        assertThat(GsonFactory.getGson(), is(GsonFactory.getGson()));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/time/TimeServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.time;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass TimeServiceTest {\n    \n    private final TimeService timeService = new TimeService();\n    \n    @Test\n    void assertGetCurrentMillis() {\n        assertTrue(timeService.getCurrentMillis() <= System.currentTimeMillis());\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/util/SensitiveInfoUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.util;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass SensitiveInfoUtilsTest {\n    \n    @Test\n    void assertFilterContentWithoutIp() {\n        List<String> actual = Arrays.asList(\"/simpleElasticDemoJob/servers\", \"/simpleElasticDemoJob/leader\");\n        assertThat(SensitiveInfoUtils.filterSensitiveIps(actual), is(actual));\n    }\n    \n    @Test\n    void assertFilterContentWithSensitiveIp() {\n        List<String> actual = Arrays.asList(\"/simpleElasticDemoJob/servers/127.0.0.1\", \"/simpleElasticDemoJob/servers/192.168.0.1/hostName | 192.168.0.1\",\n                \"/simpleElasticDemoJob/servers/192.168.0.11\", \"/simpleElasticDemoJob/servers/192.168.0.111\");\n        List<String> expected = Arrays.asList(\"/simpleElasticDemoJob/servers/ip1\", \"/simpleElasticDemoJob/servers/ip2/hostName | ip2\",\n                \"/simpleElasticDemoJob/servers/ip3\", \"/simpleElasticDemoJob/servers/ip4\");\n        assertThat(SensitiveInfoUtils.filterSensitiveIps(actual), is(expected));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/yaml/YamlEngineTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.yaml;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.fixture.FooYamlConfiguration;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass YamlEngineTest {\n    \n    private static final String YAML = \"bar: bar\\n\"\n            + \"foo: foo\\n\"\n            + \"nest:\\n\"\n            + \"  bar: nest_bar\\n\"\n            + \"  foo: nest_foo\\n\";\n    \n    private static final String YAML_WITH_NULL = \"foo: foo\\n\";\n    \n    @Test\n    void assertMarshal() {\n        FooYamlConfiguration actual = new FooYamlConfiguration();\n        actual.setFoo(\"foo\");\n        actual.setBar(\"bar\");\n        FooYamlConfiguration nest = new FooYamlConfiguration();\n        nest.setFoo(\"nest_foo\");\n        nest.setBar(\"nest_bar\");\n        actual.setNest(nest);\n        assertThat(YamlEngine.marshal(actual), is(YAML));\n    }\n    \n    @Test\n    void assertMarshalWithNullValue() {\n        FooYamlConfiguration actual = new FooYamlConfiguration();\n        actual.setFoo(\"foo\");\n        assertThat(YamlEngine.marshal(actual), is(YAML_WITH_NULL));\n    }\n    \n    @Test\n    void assertUnmarshal() {\n        FooYamlConfiguration actual = YamlEngine.unmarshal(YAML, FooYamlConfiguration.class);\n        assertThat(actual.getFoo(), is(\"foo\"));\n        assertThat(actual.getBar(), is(\"bar\"));\n        assertThat(actual.getNest().getFoo(), is(\"nest_foo\"));\n        assertThat(actual.getNest().getBar(), is(\"nest_bar\"));\n    }\n    \n    @Test\n    void assertUnmarshalWithNullValue() {\n        FooYamlConfiguration actual = YamlEngine.unmarshal(YAML_WITH_NULL, FooYamlConfiguration.class);\n        assertThat(actual.getFoo(), is(\"foo\"));\n        assertNull(actual.getBar());\n        assertNull(actual.getNest());\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/infra/yaml/fixture/FooYamlConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.infra.yaml.fixture;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\n@Getter\n@Setter\npublic final class FooYamlConfiguration {\n    \n    private String foo;\n    \n    private String bar;\n    \n    private FooYamlConfiguration nest;\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/annotation/JobAnnotationBuilderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.annotation;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.annotation.fixture.AnnotationJobFixture;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass JobAnnotationBuilderTest {\n    \n    @Test\n    void assertGenerateJobConfiguration() {\n        JobConfiguration jobConfig = JobAnnotationBuilder.generateJobConfiguration(AnnotationJobFixture.class);\n        assertThat(jobConfig.getJobName(), is(\"AnnotationJobFixture\"));\n        assertThat(jobConfig.getShardingTotalCount(), is(3));\n        assertThat(jobConfig.getShardingItemParameters(), is(\"0=a,1=b,2=c\"));\n        assertThat(jobConfig.getCron(), is(\"*/10 * * * * ?\"));\n        assertTrue(jobConfig.isMonitorExecution());\n        assertFalse(jobConfig.isFailover());\n        assertTrue(jobConfig.isMisfire());\n        assertThat(jobConfig.getMaxTimeDiffSeconds(), is(-1));\n        assertThat(jobConfig.getReconcileIntervalMinutes(), is(10));\n        assertNull(jobConfig.getJobShardingStrategyType());\n        assertNull(jobConfig.getJobExecutorThreadPoolSizeProviderType());\n        assertNull(jobConfig.getJobErrorHandlerType());\n        assertThat(jobConfig.getDescription(), is(\"desc\"));\n        assertThat(jobConfig.getProps().getProperty(\"print.title\"), is(\"test title\"));\n        assertThat(jobConfig.getProps().getProperty(\"print.content\"), is(\"test content\"));\n        assertFalse(jobConfig.isDisabled());\n        assertFalse(jobConfig.isOverwrite());\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/annotation/fixture/AnnotationJobFixture.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.annotation.fixture;\n\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobConfiguration;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobProp;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\n\n@ElasticJobConfiguration(\n        jobName = \"AnnotationJobFixture\",\n        description = \"desc\",\n        shardingTotalCount = 3,\n        shardingItemParameters = \"0=a,1=b,2=c\",\n        cron = \"*/10 * * * * ?\",\n        props = {\n                @ElasticJobProp(key = \"print.title\", value = \"test title\"),\n                @ElasticJobProp(key = \"print.content\", value = \"test content\")\n        })\npublic class AnnotationJobFixture implements ElasticJob {\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/config/ConfigurationNodeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.config;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ConfigurationNodeTest {\n    \n    private final ConfigurationNode configurationNode = new ConfigurationNode(\"test_job\");\n    \n    @Test\n    void assertIsConfigPath() {\n        assertTrue(configurationNode.isConfigPath(\"/test_job/config\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/config/ConfigurationServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.config;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobExecutionEnvironmentException;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.YamlConstants;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\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.assertThrows;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ConfigurationServiceTest {\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    private final ConfigurationService configService = new ConfigurationService(null, \"test_job\");\n    \n    @BeforeEach\n    void setUp() {\n        ReflectionUtils.setFieldValue(configService, \"jobNodeStorage\", jobNodeStorage);\n    }\n    \n    @Test\n    void assertLoadDirectly() {\n        when(jobNodeStorage.getJobNodeDataDirectly(ConfigurationNode.ROOT)).thenReturn(YamlConstants.getJobYaml());\n        JobConfiguration actual = configService.load(false);\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getCron(), is(\"0/1 * * * * ?\"));\n        assertThat(actual.getShardingTotalCount(), is(3));\n    }\n    \n    @Test\n    void assertLoadFromCache() {\n        when(jobNodeStorage.getJobNodeData(ConfigurationNode.ROOT)).thenReturn(YamlConstants.getJobYaml());\n        JobConfiguration actual = configService.load(true);\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getCron(), is(\"0/1 * * * * ?\"));\n        assertThat(actual.getShardingTotalCount(), is(3));\n    }\n    \n    @Test\n    void assertLoadFromCacheButNull() {\n        when(jobNodeStorage.getJobNodeData(ConfigurationNode.ROOT)).thenReturn(null);\n        when(jobNodeStorage.getJobNodeDataDirectly(ConfigurationNode.ROOT)).thenReturn(YamlConstants.getJobYaml());\n        JobConfiguration actual = configService.load(true);\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getCron(), is(\"0/1 * * * * ?\"));\n        assertThat(actual.getShardingTotalCount(), is(3));\n    }\n    \n    @Test\n    void assertSetUpJobConfigurationJobConfigurationForJobConflict() {\n        assertThrows(JobConfigurationException.class, () -> {\n            when(jobNodeStorage.isJobRootNodeExisted()).thenReturn(true);\n            when(jobNodeStorage.getJobRootNodeData()).thenReturn(\"org.apache.shardingsphere.elasticjob.kernel.api.script.api.ScriptJob\");\n            try {\n                configService.setUpJobConfiguration(null, JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n            } finally {\n                verify(jobNodeStorage).isJobRootNodeExisted();\n                verify(jobNodeStorage).getJobRootNodeData();\n            }\n        });\n    }\n    \n    @Test\n    void assertSetUpJobConfigurationNewJobConfiguration() {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build();\n        assertThat(configService.setUpJobConfiguration(ElasticJob.class.getName(), jobConfig), is(jobConfig));\n        verify(jobNodeStorage).replaceJobNode(\"config\", YamlEngine.marshal(JobConfigurationPOJO.fromJobConfiguration(jobConfig)));\n    }\n    \n    @Test\n    void assertSetUpJobConfigurationExistedJobConfigurationAndOverwrite() {\n        when(jobNodeStorage.isJobNodeExisted(ConfigurationNode.ROOT)).thenReturn(true);\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").overwrite(true).build();\n        assertThat(configService.setUpJobConfiguration(ElasticJob.class.getName(), jobConfig), is(jobConfig));\n        verify(jobNodeStorage).replaceJobNode(\"config\", YamlEngine.marshal(JobConfigurationPOJO.fromJobConfiguration(jobConfig)));\n    }\n    \n    @Test\n    void assertSetUpJobConfigurationExistedJobConfigurationAndNotOverwrite() {\n        when(jobNodeStorage.isJobNodeExisted(ConfigurationNode.ROOT)).thenReturn(true);\n        when(jobNodeStorage.getJobNodeDataDirectly(ConfigurationNode.ROOT)).thenReturn(\n                YamlEngine.marshal(JobConfigurationPOJO.fromJobConfiguration(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build())));\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").overwrite(false).build();\n        JobConfiguration actual = configService.setUpJobConfiguration(ElasticJob.class.getName(), jobConfig);\n        assertThat(actual, not(jobConfig));\n    }\n    \n    @Test\n    void assertIsMaxTimeDiffSecondsTolerableWithDefaultValue() throws JobExecutionEnvironmentException {\n        when(jobNodeStorage.getJobNodeData(ConfigurationNode.ROOT)).thenReturn(YamlConstants.getJobYaml(-1));\n        configService.checkMaxTimeDiffSecondsTolerable();\n    }\n    \n    @Test\n    void assertIsMaxTimeDiffSecondsTolerable() throws JobExecutionEnvironmentException {\n        when(jobNodeStorage.getJobNodeData(ConfigurationNode.ROOT)).thenReturn(YamlConstants.getJobYaml());\n        when(jobNodeStorage.getRegistryCenterTime()).thenReturn(System.currentTimeMillis());\n        configService.checkMaxTimeDiffSecondsTolerable();\n        verify(jobNodeStorage).getRegistryCenterTime();\n    }\n    \n    @Test\n    void assertIsNotMaxTimeDiffSecondsTolerable() {\n        assertThrows(JobExecutionEnvironmentException.class, () -> {\n            when(jobNodeStorage.getJobNodeData(ConfigurationNode.ROOT)).thenReturn(YamlConstants.getJobYaml());\n            when(jobNodeStorage.getRegistryCenterTime()).thenReturn(0L);\n            try {\n                configService.checkMaxTimeDiffSecondsTolerable();\n            } finally {\n                verify(jobNodeStorage).getRegistryCenterTime();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/config/JobConfigurationPOJOTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.config;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Collections;\n\nimport static org.hamcrest.CoreMatchers.hasItem;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass JobConfigurationPOJOTest {\n    \n    private static final String YAML = \"cron: 0/1 * * * * ?\\n\"\n            + \"description: Job description\\n\"\n            + \"disabled: false\\n\"\n            + \"failover: false\\n\"\n            + \"jobErrorHandlerType: IGNORE\\n\"\n            + \"jobExecutorThreadPoolSizeProviderType: CPU\\n\"\n            + \"jobName: test_job\\n\"\n            + \"jobParameter: param\\n\"\n            + \"jobShardingStrategyType: AVG_ALLOCATION\\n\"\n            + \"maxTimeDiffSeconds: -1\\n\"\n            + \"misfire: false\\n\"\n            + \"monitorExecution: false\\n\"\n            + \"overwrite: false\\n\"\n            + \"props:\\n\"\n            + \"  key: value\\n\"\n            + \"reconcileIntervalMinutes: 0\\n\"\n            + \"shardingItemParameters: 0=A,1=B,2=C\\n\"\n            + \"shardingTotalCount: 3\\n\"\n            + \"staticSharding: false\\n\";\n    \n    private static final String YAML_WITH_NULL = \"cron: 0/1 * * * * ?\\n\"\n            + \"disabled: false\\n\"\n            + \"failover: false\\n\"\n            + \"jobName: test_job\\n\"\n            + \"maxTimeDiffSeconds: -1\\n\"\n            + \"misfire: false\\n\"\n            + \"monitorExecution: false\\n\"\n            + \"overwrite: false\\n\"\n            + \"reconcileIntervalMinutes: 0\\n\"\n            + \"shardingTotalCount: 3\\n\"\n            + \"staticSharding: false\\n\";\n    \n    @Test\n    void assertToJobConfiguration() {\n        JobConfigurationPOJO pojo = new JobConfigurationPOJO();\n        pojo.setJobName(\"test_job\");\n        pojo.setCron(\"0/1 * * * * ?\");\n        pojo.setShardingTotalCount(3);\n        pojo.setShardingItemParameters(\"0=A,1=B,2=C\");\n        pojo.setJobParameter(\"param\");\n        pojo.setMonitorExecution(true);\n        pojo.setFailover(true);\n        pojo.setMisfire(true);\n        pojo.setJobShardingStrategyType(\"AVG_ALLOCATION\");\n        pojo.setJobExecutorThreadPoolSizeProviderType(\"CPU\");\n        pojo.setJobErrorHandlerType(\"IGNORE\");\n        pojo.setJobListenerTypes(Collections.singletonList(\"LOG\"));\n        pojo.setDescription(\"Job description\");\n        pojo.getProps().setProperty(\"key\", \"value\");\n        pojo.setDisabled(true);\n        pojo.setOverwrite(true);\n        JobConfiguration actual = pojo.toJobConfiguration();\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getCron(), is(\"0/1 * * * * ?\"));\n        assertThat(actual.getShardingTotalCount(), is(3));\n        assertThat(actual.getShardingItemParameters(), is(\"0=A,1=B,2=C\"));\n        assertThat(actual.getJobParameter(), is(\"param\"));\n        assertTrue(actual.isMonitorExecution());\n        assertTrue(actual.isFailover());\n        assertTrue(actual.isMisfire());\n        assertThat(actual.getJobShardingStrategyType(), is(\"AVG_ALLOCATION\"));\n        assertThat(actual.getJobExecutorThreadPoolSizeProviderType(), is(\"CPU\"));\n        assertThat(actual.getJobErrorHandlerType(), is(\"IGNORE\"));\n        assertThat(actual.getJobListenerTypes(), hasItem(\"LOG\"));\n        assertThat(actual.getDescription(), is(\"Job description\"));\n        assertThat(actual.getProps().getProperty(\"key\"), is(\"value\"));\n        assertTrue(actual.isDisabled());\n        assertTrue(actual.isOverwrite());\n    }\n    \n    @Test\n    void assertFromJobConfiguration() {\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"test_job\", 3)\n                .cron(\"0/1 * * * * ?\")\n                .shardingItemParameters(\"0=A,1=B,2=C\").jobParameter(\"param\")\n                .monitorExecution(true).failover(true).misfire(true)\n                .jobShardingStrategyType(\"AVG_ALLOCATION\").jobExecutorThreadPoolSizeProviderType(\"CPU\").jobErrorHandlerType(\"IGNORE\")\n                .jobListenerTypes(\"LOG\").description(\"Job description\").setProperty(\"key\", \"value\")\n                .disabled(true).overwrite(true).build();\n        JobConfigurationPOJO actual = JobConfigurationPOJO.fromJobConfiguration(jobConfig);\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getCron(), is(\"0/1 * * * * ?\"));\n        assertThat(actual.getShardingTotalCount(), is(3));\n        assertThat(actual.getShardingItemParameters(), is(\"0=A,1=B,2=C\"));\n        assertThat(actual.getJobParameter(), is(\"param\"));\n        assertTrue(actual.isMonitorExecution());\n        assertTrue(actual.isFailover());\n        assertTrue(actual.isMisfire());\n        assertThat(actual.getJobShardingStrategyType(), is(\"AVG_ALLOCATION\"));\n        assertThat(actual.getJobExecutorThreadPoolSizeProviderType(), is(\"CPU\"));\n        assertThat(actual.getJobErrorHandlerType(), is(\"IGNORE\"));\n        assertThat(actual.getJobListenerTypes(), hasItem(\"LOG\"));\n        assertThat(actual.getDescription(), is(\"Job description\"));\n        assertThat(actual.getProps().getProperty(\"key\"), is(\"value\"));\n        assertTrue(actual.isDisabled());\n        assertTrue(actual.isOverwrite());\n    }\n    \n    @Test\n    void assertMarshal() {\n        JobConfigurationPOJO actual = new JobConfigurationPOJO();\n        actual.setJobName(\"test_job\");\n        actual.setCron(\"0/1 * * * * ?\");\n        actual.setShardingTotalCount(3);\n        actual.setShardingItemParameters(\"0=A,1=B,2=C\");\n        actual.setJobParameter(\"param\");\n        actual.setMaxTimeDiffSeconds(-1);\n        actual.setJobShardingStrategyType(\"AVG_ALLOCATION\");\n        actual.setJobExecutorThreadPoolSizeProviderType(\"CPU\");\n        actual.setJobErrorHandlerType(\"IGNORE\");\n        actual.setDescription(\"Job description\");\n        actual.getProps().setProperty(\"key\", \"value\");\n        assertThat(YamlEngine.marshal(actual), is(YAML));\n    }\n    \n    @Test\n    void assertMarshalWithNullValue() {\n        JobConfigurationPOJO actual = new JobConfigurationPOJO();\n        actual.setJobName(\"test_job\");\n        actual.setCron(\"0/1 * * * * ?\");\n        actual.setShardingTotalCount(3);\n        actual.setMaxTimeDiffSeconds(-1);\n        assertThat(YamlEngine.marshal(actual), is(YAML_WITH_NULL));\n    }\n    \n    @Test\n    void assertUnmarshal() {\n        JobConfigurationPOJO actual = YamlEngine.unmarshal(YAML, JobConfigurationPOJO.class);\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getCron(), is(\"0/1 * * * * ?\"));\n        assertThat(actual.getShardingTotalCount(), is(3));\n        assertThat(actual.getShardingItemParameters(), is(\"0=A,1=B,2=C\"));\n        assertThat(actual.getJobParameter(), is(\"param\"));\n        assertFalse(actual.isMonitorExecution());\n        assertFalse(actual.isFailover());\n        assertFalse(actual.isMisfire());\n        assertThat(actual.getJobShardingStrategyType(), is(\"AVG_ALLOCATION\"));\n        assertThat(actual.getJobExecutorThreadPoolSizeProviderType(), is(\"CPU\"));\n        assertThat(actual.getJobErrorHandlerType(), is(\"IGNORE\"));\n        assertThat(actual.getDescription(), is(\"Job description\"));\n        assertThat(actual.getProps().getProperty(\"key\"), is(\"value\"));\n    }\n    \n    @Test\n    void assertUnmarshalWithNullValue() {\n        JobConfigurationPOJO actual = YamlEngine.unmarshal(YAML_WITH_NULL, JobConfigurationPOJO.class);\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getCron(), is(\"0/1 * * * * ?\"));\n        assertThat(actual.getShardingTotalCount(), is(3));\n        assertNull(actual.getShardingItemParameters());\n        assertNull(actual.getJobParameter());\n        assertFalse(actual.isMonitorExecution());\n        assertFalse(actual.isFailover());\n        assertFalse(actual.isMisfire());\n        assertNull(actual.getJobShardingStrategyType());\n        assertNull(actual.getJobExecutorThreadPoolSizeProviderType());\n        assertNull(actual.getJobErrorHandlerType());\n        assertNull(actual.getDescription());\n        assertTrue(actual.getProps().isEmpty());\n        assertFalse(actual.isDisabled());\n        assertFalse(actual.isOverwrite());\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/config/RescheduleListenerManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.config;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.YamlConstants;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass RescheduleListenerManagerTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    private final RescheduleListenerManager rescheduleListenerManager = new RescheduleListenerManager(null, \"test_job\");\n    \n    @BeforeEach\n    void setUp() {\n        ReflectionUtils.setSuperclassFieldValue(rescheduleListenerManager, \"jobNodeStorage\", jobNodeStorage);\n    }\n    \n    @Test\n    void assertStart() {\n        rescheduleListenerManager.start();\n        verify(jobNodeStorage).addDataListener(ArgumentMatchers.<RescheduleListenerManager.CronSettingAndJobEventChangedJobListener>any());\n    }\n    \n    @Test\n    void assertCronSettingChangedJobListenerWhenIsNotCronPath() {\n        rescheduleListenerManager.new CronSettingAndJobEventChangedJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.ADDED, \"/test_job/config/other\", YamlConstants.getJobYaml()));\n        verify(jobScheduleController, times(0)).rescheduleJob(any(), any());\n    }\n    \n    @Test\n    void assertCronSettingChangedJobListenerWhenIsCronPathButNotUpdate() {\n        rescheduleListenerManager.new CronSettingAndJobEventChangedJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.ADDED, \"/test_job/config\", YamlConstants.getJobYaml()));\n        verify(jobScheduleController, times(0)).rescheduleJob(any(), any());\n    }\n    \n    @Test\n    void assertCronSettingChangedJobListenerWhenIsCronPathAndUpdateButCannotFindJob() {\n        rescheduleListenerManager.new CronSettingAndJobEventChangedJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.UPDATED, \"/test_job/config\", YamlConstants.getJobYaml()));\n        verify(jobScheduleController, times(0)).rescheduleJob(any(), any());\n    }\n    \n    @Test\n    void assertCronSettingChangedJobListenerWhenIsCronPathAndUpdateAndFindJob() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        rescheduleListenerManager.new CronSettingAndJobEventChangedJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.UPDATED, \"/test_job/config\", YamlConstants.getJobYaml()));\n        verify(jobScheduleController).rescheduleJob(\"0/1 * * * * ?\", null);\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/context/TaskContextTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.context;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.ExecutionType;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.context.TaskContext.MetaInfo;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.context.fixture.TaskNode;\nimport org.hamcrest.CoreMatchers;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Collections;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.startsWith;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass TaskContextTest {\n    \n    @Test\n    void assertNew() {\n        TaskContext actual = new TaskContext(\"test_job\", Collections.singletonList(0), ExecutionType.READY, \"slave-S0\");\n        assertThat(actual.getMetaInfo().getJobName(), is(\"test_job\"));\n        assertThat(actual.getMetaInfo().getShardingItems().get(0), is(0));\n        assertThat(actual.getType(), CoreMatchers.is(ExecutionType.READY));\n        assertThat(actual.getSlaveId(), is(\"slave-S0\"));\n        assertThat(actual.getId(), startsWith(TaskNode.builder().build().getTaskNodeValue().substring(0, TaskNode.builder().build().getTaskNodeValue().length() - 1)));\n    }\n    \n    @Test\n    void assertNewWithoutSlaveId() {\n        TaskContext actual = new TaskContext(\"test_job\", Collections.singletonList(0), ExecutionType.READY);\n        assertThat(actual.getSlaveId(), is(\"unassigned-slave\"));\n    }\n    \n    @Test\n    void assertGetMetaInfo() {\n        TaskContext actual = new TaskContext(\"test_job\", Collections.singletonList(0), ExecutionType.READY, \"slave-S0\");\n        assertThat(actual.getMetaInfo().toString(), is(\"test_job@-@0\"));\n    }\n    \n    @Test\n    void assertTaskContextFrom() {\n        TaskContext actual = TaskContext.from(TaskNode.builder().build().getTaskNodeValue());\n        assertThat(actual.getId(), is(TaskNode.builder().build().getTaskNodeValue()));\n        assertThat(actual.getMetaInfo().getJobName(), is(\"test_job\"));\n        assertThat(actual.getMetaInfo().getShardingItems().get(0), is(0));\n        assertThat(actual.getType(), CoreMatchers.is(ExecutionType.READY));\n        assertThat(actual.getSlaveId(), is(\"slave-S0\"));\n    }\n    \n    @Test\n    void assertMetaInfoFromWithMetaInfo() {\n        MetaInfo actual = MetaInfo.from(\"test_job@-@1\");\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getShardingItems().get(0), is(1));\n    }\n    \n    @Test\n    void assertMetaInfoFromWithTaskId() {\n        MetaInfo actual = MetaInfo.from(\"test_job@-@1@-@READY@-@unassigned-slave@-@0\");\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getShardingItems().get(0), is(1));\n    }\n    \n    @Test\n    void assertMetaInfoFromWithMetaInfoWithoutShardingItems() {\n        MetaInfo actual = MetaInfo.from(\"test_job@-@\");\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertTrue(actual.getShardingItems().isEmpty());\n    }\n    \n    @Test\n    void assertMetaInfoFromWithTaskIdWithoutShardingItems() {\n        MetaInfo actual = MetaInfo.from(\"test_job@-@@-@READY@-@unassigned-slave@-@0\");\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertTrue(actual.getShardingItems().isEmpty());\n    }\n    \n    @Test\n    void assertGetIdForUnassignedSlave() {\n        assertThat(TaskContext.getIdForUnassignedSlave(\"test_job@-@0@-@READY@-@slave-S0@-@0\"), is(\"test_job@-@0@-@READY@-@unassigned-slave@-@0\"));\n    }\n    \n    @Test\n    void assertGetTaskName() {\n        TaskContext actual = TaskContext.from(TaskNode.builder().build().getTaskNodeValue());\n        assertThat(actual.getTaskName(), is(\"test_job@-@0@-@READY@-@slave-S0\"));\n    }\n    \n    @Test\n    void assertGetExecutorId() {\n        TaskContext actual = TaskContext.from(TaskNode.builder().build().getTaskNodeValue());\n        assertThat(actual.getExecutorId(\"app\"), is(\"app@-@slave-S0\"));\n    }\n    \n    @Test\n    void assertSetSlaveId() {\n        TaskContext actual = new TaskContext(\"test_job\", Collections.singletonList(0), ExecutionType.READY, \"slave-S0\");\n        assertThat(actual.getSlaveId(), is(\"slave-S0\"));\n        actual.setSlaveId(\"slave-S1\");\n        assertThat(actual.getSlaveId(), is(\"slave-S1\"));\n    }\n    \n    @Test\n    void assertSetIdle() {\n        TaskContext actual = new TaskContext(\"test_job\", Collections.singletonList(0), ExecutionType.READY, \"slave-S0\");\n        assertFalse(actual.isIdle());\n        actual.setIdle(true);\n        assertTrue(actual.isIdle());\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/context/fixture/TaskNode.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.context.fixture;\n\nimport lombok.Builder;\nimport org.apache.shardingsphere.elasticjob.spi.executor.ExecutionType;\n\n@Builder\npublic final class TaskNode {\n    \n    private final String jobName;\n    \n    private final int shardingItem;\n    \n    private final ExecutionType type;\n    \n    private final String slaveId;\n    \n    private final String uuid;\n    \n    /**\n     * Get the value of task node.\n     *\n     * @return the value of task node\n     */\n    public String getTaskNodeValue() {\n        return String.join(\"@-@\", getTaskNodePath(), null == type ? ExecutionType.READY.toString() : type.toString(), null == slaveId ? \"slave-S0\" : slaveId, null == uuid ? \"0\" : uuid);\n    }\n    \n    private String getTaskNodePath() {\n        return String.join(\"@-@\", null == jobName ? \"test_job\" : jobName, String.valueOf(shardingItem));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/election/ElectionListenerManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.election;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerStatus;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ElectionListenerManagerTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private LeaderService leaderService;\n    \n    @Mock\n    private ServerService serverService;\n    \n    private final ElectionListenerManager electionListenerManager = new ElectionListenerManager(null, \"test_job\");\n    \n    @BeforeEach\n    void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\", null, \"127.0.0.1\"));\n        ReflectionUtils.setSuperclassFieldValue(electionListenerManager, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(electionListenerManager, \"leaderService\", leaderService);\n        ReflectionUtils.setFieldValue(electionListenerManager, \"serverService\", serverService);\n    }\n    \n    @Test\n    void assertStart() {\n        electionListenerManager.start();\n        verify(jobNodeStorage, times(2)).addDataListener(ArgumentMatchers.<ElectionListenerManager.LeaderElectionJobListener>any());\n    }\n    \n    @Test\n    void assertIsNotLeaderInstancePathAndServerPath() {\n        electionListenerManager.new LeaderElectionJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.DELETED, \"/test_job/leader/election/other\", \"127.0.0.1\"));\n        verify(leaderService, times(0)).electLeader();\n    }\n    \n    @Test\n    void assertLeaderElectionWhenAddLeaderInstancePath() {\n        electionListenerManager.new LeaderElectionJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/leader/election/instance\", \"127.0.0.1\"));\n        verify(leaderService, times(0)).electLeader();\n    }\n    \n    @Test\n    void assertLeaderElectionWhenRemoveLeaderInstancePathWithoutAvailableServers() {\n        electionListenerManager.new LeaderElectionJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/leader/election/instance\", \"127.0.0.1\"));\n        verify(leaderService, times(0)).electLeader();\n    }\n    \n    @Test\n    void assertLeaderElectionWhenRemoveLeaderInstancePathWithAvailableServerButJobInstanceIsShutdown() {\n        electionListenerManager.new LeaderElectionJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/leader/election/instance\", \"127.0.0.1\"));\n        verify(leaderService, times(0)).electLeader();\n    }\n    \n    @Test\n    void assertLeaderElectionWhenRemoveLeaderInstancePathWithAvailableServer() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(serverService.isAvailableServer(\"127.0.0.1\")).thenReturn(true);\n        electionListenerManager.new LeaderElectionJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/leader/election/instance\", \"127.0.0.1\"));\n        verify(leaderService).electLeader();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertLeaderElectionWhenServerDisableWithoutLeader() {\n        electionListenerManager.new LeaderElectionJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/servers/127.0.0.1\", ServerStatus.DISABLED.name()));\n        verify(leaderService, times(0)).electLeader();\n    }\n    \n    @Test\n    void assertLeaderElectionWhenServerEnableWithLeader() {\n        electionListenerManager.new LeaderElectionJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/servers/127.0.0.1\", \"\"));\n        verify(leaderService, times(0)).electLeader();\n    }\n    \n    @Test\n    void assertLeaderElectionWhenServerEnableWithoutLeader() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        electionListenerManager.new LeaderElectionJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/servers/127.0.0.1\", \"\"));\n        verify(leaderService).electLeader();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertLeaderAbdicationWhenFollowerDisable() {\n        electionListenerManager.new LeaderAbdicationJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/servers/127.0.0.1\", ServerStatus.DISABLED.name()));\n        verify(leaderService, times(0)).removeLeader();\n    }\n    \n    @Test\n    void assertLeaderAbdicationWhenLeaderDisable() {\n        when(leaderService.isLeader()).thenReturn(true);\n        electionListenerManager.new LeaderAbdicationJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/servers/127.0.0.1\", ServerStatus.DISABLED.name()));\n        verify(leaderService).removeLeader();\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/election/LeaderNodeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.election;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass LeaderNodeTest {\n    \n    private final LeaderNode leaderNode = new LeaderNode(\"test_job\");\n    \n    @Test\n    void assertIsLeaderInstancePath() {\n        assertTrue(leaderNode.isLeaderInstancePath(\"/test_job/leader/election/instance\"));\n    }\n    \n    @Test\n    void assertIsNotLeaderInstancePath() {\n        assertFalse(leaderNode.isLeaderInstancePath(\"/test_job/leader/election/instance1\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/election/LeaderServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.election;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderService.LeaderElectionExecutionCallback;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass LeaderServiceTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private ServerService serverService;\n    \n    private LeaderService leaderService;\n    \n    @BeforeEach\n    void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\", null, \"127.0.0.1\"));\n        leaderService = new LeaderService(null, \"test_job\");\n        ReflectionUtils.setFieldValue(leaderService, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(leaderService, \"serverService\", serverService);\n    }\n    \n    @Test\n    void assertElectLeader() {\n        leaderService.electLeader();\n        verify(jobNodeStorage).executeInLeader(eq(\"leader/election/latch\"), ArgumentMatchers.<LeaderElectionExecutionCallback>any());\n    }\n    \n    @Test\n    void assertIsLeaderUntilBlockWithLeader() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(jobNodeStorage.isJobNodeExisted(\"leader/election/instance\")).thenReturn(true);\n        when(jobNodeStorage.getJobNodeData(\"leader/election/instance\")).thenReturn(\"127.0.0.1@-@0\");\n        assertTrue(leaderService.isLeaderUntilBlock());\n        verify(jobNodeStorage, times(0)).executeInLeader(eq(\"leader/election/latch\"), ArgumentMatchers.<LeaderElectionExecutionCallback>any());\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertIsLeaderUntilBlockWithoutLeaderAndAvailableServers() {\n        when(jobNodeStorage.isJobNodeExisted(\"leader/election/instance\")).thenReturn(false);\n        assertFalse(leaderService.isLeaderUntilBlock());\n        verify(jobNodeStorage, times(0)).executeInLeader(eq(\"leader/election/latch\"), ArgumentMatchers.<LeaderElectionExecutionCallback>any());\n    }\n    \n    @Test\n    void assertIsLeaderUntilBlockWithoutLeaderWithAvailableServers() {\n        when(jobNodeStorage.isJobNodeExisted(\"leader/election/instance\")).thenReturn(false, true);\n        assertFalse(leaderService.isLeaderUntilBlock());\n        verify(jobNodeStorage, times(0)).executeInLeader(eq(\"leader/election/latch\"), ArgumentMatchers.<LeaderElectionExecutionCallback>any());\n    }\n    \n    @Test\n    void assertIsLeaderUntilBlockWhenHasLeader() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(jobNodeStorage.isJobNodeExisted(\"leader/election/instance\")).thenReturn(false, true);\n        when(serverService.hasAvailableServers()).thenReturn(true);\n        when(serverService.isAvailableServer(\"127.0.0.1\")).thenReturn(true);\n        when(jobNodeStorage.getJobNodeData(\"leader/election/instance\")).thenReturn(\"127.0.0.1@-@0\");\n        assertTrue(leaderService.isLeaderUntilBlock());\n        verify(jobNodeStorage).executeInLeader(eq(\"leader/election/latch\"), ArgumentMatchers.<LeaderElectionExecutionCallback>any());\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertIsLeader() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(jobNodeStorage.getJobNodeData(\"leader/election/instance\")).thenReturn(\"127.0.0.1@-@0\");\n        assertTrue(leaderService.isLeader());\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertHasLeader() {\n        when(jobNodeStorage.isJobNodeExisted(\"leader/election/instance\")).thenReturn(true);\n        assertTrue(leaderService.hasLeader());\n    }\n    \n    @Test\n    void assertRemoveLeader() {\n        leaderService.removeLeader();\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"leader/election/instance\");\n    }\n    \n    @Test\n    void assertElectLeaderExecutionCallbackWithLeader() {\n        when(jobNodeStorage.isJobNodeExisted(\"leader/election/instance\")).thenReturn(true);\n        leaderService.new LeaderElectionExecutionCallback().execute();\n        verify(jobNodeStorage, times(0)).fillEphemeralJobNode(\"leader/election/instance\", \"127.0.0.1@-@0\");\n    }\n    \n    @Test\n    void assertElectLeaderExecutionCallbackWithoutLeader() {\n        leaderService.new LeaderElectionExecutionCallback().execute();\n        verify(jobNodeStorage).fillEphemeralJobNode(\"leader/election/instance\", \"127.0.0.1@-@0\");\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/failover/FailoverListenerManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.failover;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.YamlConstants;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.verifyNoInteractions;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass FailoverListenerManagerTest {\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    @Mock\n    private ConfigurationService configService;\n    \n    @Mock\n    private ShardingService shardingService;\n    \n    @Mock\n    private FailoverService failoverService;\n    \n    @Mock\n    private InstanceService instanceService;\n    \n    @Mock\n    private ExecutionService executionService;\n    \n    @Mock\n    private InstanceNode instanceNode;\n    \n    private final FailoverListenerManager failoverListenerManager = new FailoverListenerManager(null, \"test_job\");\n    \n    @BeforeEach\n    void setUp() {\n        ReflectionUtils.setSuperclassFieldValue(failoverListenerManager, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(failoverListenerManager, \"configService\", configService);\n        ReflectionUtils.setFieldValue(failoverListenerManager, \"shardingService\", shardingService);\n        ReflectionUtils.setFieldValue(failoverListenerManager, \"failoverService\", failoverService);\n        ReflectionUtils.setFieldValue(failoverListenerManager, \"instanceService\", instanceService);\n        ReflectionUtils.setFieldValue(failoverListenerManager, \"executionService\", executionService);\n        ReflectionUtils.setFieldValue(failoverListenerManager, \"instanceNode\", instanceNode);\n    }\n    \n    @Test\n    void assertStart() {\n        failoverListenerManager.start();\n        verify(jobNodeStorage, times(3)).addDataListener(ArgumentMatchers.any(DataChangedEventListener.class));\n    }\n    \n    @Test\n    void assertJobCrashedJobListenerWhenFailoverDisabled() {\n        failoverListenerManager.new JobCrashedJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/instances/127.0.0.1@-@0\", \"\"));\n        verify(failoverService, times(0)).failoverIfNecessary();\n    }\n    \n    @Test\n    void assertJobCrashedJobListenerWhenIsNotNodeRemoved() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).build());\n        failoverListenerManager.new JobCrashedJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/instances/127.0.0.1@-@0\", \"\"));\n        verify(failoverService, times(0)).failoverIfNecessary();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertJobCrashedJobListenerWhenIsNotInstancesPath() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).build());\n        failoverListenerManager.new JobCrashedJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/other/127.0.0.1@-@0\", \"\"));\n        verify(failoverService, times(0)).failoverIfNecessary();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertJobCrashedJobListenerWhenIsSameInstance() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).build());\n        failoverListenerManager.new JobCrashedJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/instances/127.0.0.1@-@0\", \"\"));\n        verify(failoverService, times(0)).failoverIfNecessary();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertJobCrashedJobListenerWhenIsOtherInstanceCrashed() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).build());\n        when(shardingService.getCrashedShardingItems(\"127.0.0.1@-@1\")).thenReturn(Arrays.asList(0, 2));\n        when(instanceNode.isInstancePath(\"/test_job/instances/127.0.0.1@-@1\")).thenReturn(true);\n        when(instanceNode.getInstanceFullPath()).thenReturn(\"/test_job/instances\");\n        failoverListenerManager.new JobCrashedJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/instances/127.0.0.1@-@1\", \"\"));\n        verify(failoverService).setCrashedFailoverFlag(0);\n        verify(failoverService).setCrashedFailoverFlag(2);\n        verify(failoverService, times(2)).failoverIfNecessary();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertJobCrashedJobListenerWhenIsOtherFailoverInstanceCrashed() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).build());\n        when(failoverService.getFailoveringItems(\"127.0.0.1@-@1\")).thenReturn(Collections.singletonList(1));\n        when(instanceNode.isInstancePath(\"/test_job/instances/127.0.0.1@-@1\")).thenReturn(true);\n        when(instanceNode.getInstanceFullPath()).thenReturn(\"/test_job/instances\");\n        failoverListenerManager.new JobCrashedJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/instances/127.0.0.1@-@1\", \"\"));\n        verify(failoverService).setCrashedFailoverFlagDirectly(1);\n        verify(executionService).clearRunningInfo(Collections.singletonList(1));\n        verify(failoverService).failoverIfNecessary();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertFailoverSettingsChangedJobListenerWhenIsNotFailoverPath() {\n        failoverListenerManager.new FailoverSettingsChangedJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/other\", YamlConstants.getJobYaml()));\n        verify(failoverService, times(0)).removeFailoverInfo();\n    }\n    \n    @Test\n    void assertFailoverSettingsChangedJobListenerWhenIsFailoverPathButNotUpdate() {\n        failoverListenerManager.new FailoverSettingsChangedJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/config\", \"\"));\n        verify(failoverService, times(0)).removeFailoverInfo();\n    }\n    \n    @Test\n    void assertFailoverSettingsChangedJobListenerWhenIsFailoverPathAndUpdateButEnableFailover() {\n        failoverListenerManager.new FailoverSettingsChangedJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/config\", YamlConstants.getJobYaml()));\n        verify(failoverService, times(0)).removeFailoverInfo();\n    }\n    \n    @Test\n    void assertFailoverSettingsChangedJobListenerWhenIsFailoverPathAndUpdateButDisableFailover() {\n        failoverListenerManager.new FailoverSettingsChangedJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/config\", YamlConstants.getJobYamlWithFailover(false)));\n        verify(failoverService).removeFailoverInfo();\n    }\n    \n    @Test\n    void assertLegacyCrashedRunningItemListenerWhenRunningItemsArePresent() {\n        JobInstance jobInstance = new JobInstance(\"127.0.0.1@-@1\");\n        JobRegistry.getInstance().registerJob(\"test_job\", mock(JobScheduleController.class));\n        JobRegistry.getInstance().addJobInstance(\"test_job\", jobInstance);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).build());\n        when(instanceNode.getLocalInstancePath()).thenReturn(\"instances/127.0.0.1@-@1\");\n        when(instanceService.getAvailableJobInstances()).thenReturn(Collections.singletonList(jobInstance));\n        Map<Integer, JobInstance> allRunningItems = new LinkedHashMap<>(2, 1);\n        allRunningItems.put(0, new JobInstance(\"127.0.0.1@-@2\"));\n        allRunningItems.put(1, new JobInstance(\"127.0.0.1@-@2\"));\n        when(executionService.getAllRunningItems()).thenReturn(allRunningItems);\n        when(failoverService.getAllFailoveringItems()).thenReturn(Collections.singletonMap(1, new JobInstance(\"127.0.0.1@-@2\")));\n        failoverListenerManager.new LegacyCrashedRunningItemListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/instances/127.0.0.1@-@1\", \"\"));\n        verify(failoverService).setCrashedFailoverFlagDirectly(1);\n        verify(failoverService).clearFailoveringItem(1);\n        verify(executionService).clearRunningInfo(Collections.singletonList(1));\n        verify(failoverService).setCrashedFailoverFlag(0);\n        verify(executionService).clearRunningInfo(Collections.singletonList(0));\n        verify(failoverService).failoverIfNecessary();\n    }\n    \n    @Test\n    void assertLegacyCrashedRunningItemListenerWhenJobInstanceAbsent() {\n        failoverListenerManager.new LegacyCrashedRunningItemListener().onChange(new DataChangedEvent(Type.ADDED, \"\", \"\"));\n        verifyNoInteractions(instanceNode);\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/failover/FailoverNodeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.failover;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass FailoverNodeTest {\n    \n    private final FailoverNode failoverNode = new FailoverNode(\"test_job\");\n    \n    @Test\n    void assertGetItemsNode() {\n        assertThat(FailoverNode.getItemsNode(0), is(\"leader/failover/items/0\"));\n    }\n    \n    @Test\n    void assertGetExecutionFailoverNode() {\n        assertThat(FailoverNode.getExecutionFailoverNode(0), is(\"sharding/0/failover\"));\n    }\n    \n    @Test\n    void assertGetItemWhenNotExecutionFailoverPath() {\n        assertNull(failoverNode.getItemByExecutionFailoverPath(\"/test_job/sharding/0/completed\"));\n    }\n    \n    @Test\n    void assertGetItemByExecutionFailoverPath() {\n        assertThat(failoverNode.getItemByExecutionFailoverPath(\"/test_job/sharding/0/failover\"), is(0));\n    }\n    \n    @Test\n    void assertGetProcessingFailoverNode() {\n        assertThat(FailoverNode.getExecutingFailoverNode(0), is(\"sharding/0/failovering\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/failover/FailoverServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.failover;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.lenient;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass FailoverServiceTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private ShardingService shardingService;\n    \n    @Mock\n    private ConfigurationService configService;\n    \n    private final FailoverService failoverService = new FailoverService(null, \"test_job\");\n    \n    @BeforeEach\n    void setUp() {\n        ReflectionUtils.setFieldValue(failoverService, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(failoverService, \"shardingService\", shardingService);\n        ReflectionUtils.setFieldValue(failoverService, \"jobName\", \"test_job\");\n        ReflectionUtils.setFieldValue(failoverService, \"configService\", configService);\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n    }\n    \n    @Test\n    void assertSetCrashedFailoverFlagWhenItemIsNotAssigned() {\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/failover\")).thenReturn(true);\n        failoverService.setCrashedFailoverFlag(0);\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/0/failover\");\n        verify(jobNodeStorage, times(0)).createJobNodeIfNeeded(\"leader/failover/items/0\");\n    }\n    \n    @Test\n    void assertSetCrashedFailoverFlagWhenItemIsAssigned() {\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/failover\")).thenReturn(false);\n        failoverService.setCrashedFailoverFlag(0);\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/0/failover\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"leader/failover/items/0\");\n    }\n    \n    @Test\n    void assertSetCrashedFailoverFlagDirectly() {\n        failoverService.setCrashedFailoverFlagDirectly(0);\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"leader/failover/items/0\");\n    }\n    \n    @Test\n    void assertFailoverIfUnnecessaryWhenItemsRootNodeNotExisted() {\n        when(jobNodeStorage.isJobNodeExisted(\"leader/failover/items\")).thenReturn(false);\n        failoverService.failoverIfNecessary();\n        verify(jobNodeStorage).isJobNodeExisted(\"leader/failover/items\");\n        verify(jobNodeStorage, times(0)).executeInLeader(eq(\"leader/failover/latch\"), ArgumentMatchers.<FailoverService.FailoverLeaderExecutionCallback>any());\n    }\n    \n    @Test\n    void assertFailoverIfUnnecessaryWhenItemsRootNodeIsEmpty() {\n        when(jobNodeStorage.isJobNodeExisted(\"leader/failover/items\")).thenReturn(true);\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"leader/failover/items\")).thenReturn(Collections.emptyList());\n        failoverService.failoverIfNecessary();\n        verify(jobNodeStorage).isJobNodeExisted(\"leader/failover/items\");\n        verify(jobNodeStorage).getJobNodeChildrenKeys(\"leader/failover/items\");\n        verify(jobNodeStorage, times(0)).executeInLeader(eq(\"leader/failover/latch\"), ArgumentMatchers.<FailoverService.FailoverLeaderExecutionCallback>any());\n    }\n    \n    @Test\n    void assertFailoverIfUnnecessaryWhenServerIsNotReady() {\n        JobRegistry.getInstance().setJobRunning(\"test_job\", true);\n        when(jobNodeStorage.isJobNodeExisted(\"leader/failover/items\")).thenReturn(true);\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"leader/failover/items\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        failoverService.failoverIfNecessary();\n        verify(jobNodeStorage).isJobNodeExisted(\"leader/failover/items\");\n        verify(jobNodeStorage).getJobNodeChildrenKeys(\"leader/failover/items\");\n        verify(jobNodeStorage, times(0)).executeInLeader(eq(\"leader/failover/latch\"), ArgumentMatchers.<FailoverService.FailoverLeaderExecutionCallback>any());\n    }\n    \n    @Test\n    void assertFailoverIfNecessary() {\n        JobRegistry.getInstance().setJobRunning(\"test_job\", false);\n        when(jobNodeStorage.isJobNodeExisted(\"leader/failover/items\")).thenReturn(true);\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"leader/failover/items\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        failoverService.failoverIfNecessary();\n        verify(jobNodeStorage).isJobNodeExisted(\"leader/failover/items\");\n        verify(jobNodeStorage).getJobNodeChildrenKeys(\"leader/failover/items\");\n        verify(jobNodeStorage).executeInLeader(eq(\"leader/failover/latch\"), ArgumentMatchers.<FailoverService.FailoverLeaderExecutionCallback>any());\n        JobRegistry.getInstance().setJobRunning(\"test_job\", false);\n    }\n    \n    @Test\n    void assertFailoverLeaderExecutionCallbackIfNotNecessary() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        JobRegistry.getInstance().setJobRunning(\"test_job\", false);\n        when(jobNodeStorage.isJobNodeExisted(\"leader/failover/items\")).thenReturn(false);\n        failoverService.new FailoverLeaderExecutionCallback().execute();\n        verify(jobNodeStorage).isJobNodeExisted(\"leader/failover/items\");\n        verify(jobNodeStorage, times(0)).getJobNodeChildrenKeys(\"leader/failover/items\");\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertFailoverLeaderExecutionCallbackIfNecessary() {\n        JobRegistry.getInstance().setJobRunning(\"test_job\", false);\n        when(jobNodeStorage.isJobNodeExisted(\"leader/failover/items\")).thenReturn(true);\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"leader/failover/items\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        failoverService.new FailoverLeaderExecutionCallback().execute();\n        verify(jobNodeStorage).isJobNodeExisted(\"leader/failover/items\");\n        verify(jobNodeStorage, times(2)).getJobNodeChildrenKeys(\"leader/failover/items\");\n        verify(jobNodeStorage).fillEphemeralJobNode(\"sharding/0/failover\", \"127.0.0.1@-@0\");\n        verify(jobNodeStorage).fillJobNode(\"sharding/0/failovering\", \"127.0.0.1@-@0\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"leader/failover/items/0\");\n        verify(jobScheduleController).triggerJob();\n        JobRegistry.getInstance().setJobRunning(\"test_job\", false);\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertGetFailoveringItems() {\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"sharding\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/failovering\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/failovering\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/2/failovering\")).thenReturn(false);\n        when(jobNodeStorage.getJobNodeDataDirectly(\"sharding/0/failovering\")).thenReturn(\"127.0.0.1@-@0\");\n        when(jobNodeStorage.getJobNodeDataDirectly(\"sharding/1/failovering\")).thenReturn(\"127.0.0.1@-@1\");\n        assertThat(failoverService.getFailoveringItems(\"127.0.0.1@-@1\"), is(Collections.singletonList(1)));\n        verify(jobNodeStorage).getJobNodeChildrenKeys(\"sharding\");\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/0/failovering\");\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/1/failovering\");\n        verify(jobNodeStorage).getJobNodeDataDirectly(\"sharding/0/failovering\");\n        verify(jobNodeStorage).getJobNodeDataDirectly(\"sharding/1/failovering\");\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertUpdateFailoverComplete() {\n        failoverService.updateFailoverComplete(Arrays.asList(0, 1));\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/0/failover\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/1/failover\");\n    }\n    \n    @Test\n    void assertGetFailoverItems() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"sharding\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/failover\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/failover\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/2/failover\")).thenReturn(false);\n        when(jobNodeStorage.getJobNodeDataDirectly(\"sharding/0/failover\")).thenReturn(\"127.0.0.1@-@0\");\n        when(jobNodeStorage.getJobNodeDataDirectly(\"sharding/1/failover\")).thenReturn(\"127.0.0.1@-@1\");\n        assertThat(failoverService.getFailoverItems(\"127.0.0.1@-@1\"), is(Collections.singletonList(1)));\n        verify(jobNodeStorage).getJobNodeChildrenKeys(\"sharding\");\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/0/failover\");\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/1/failover\");\n        verify(jobNodeStorage).getJobNodeDataDirectly(\"sharding/0/failover\");\n        verify(jobNodeStorage).getJobNodeDataDirectly(\"sharding/1/failover\");\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertGetLocalFailoverItemsIfShutdown() {\n        assertThat(failoverService.getLocalFailoverItems(), is(Collections.<Integer>emptyList()));\n        verify(jobNodeStorage, times(0)).getJobNodeChildrenKeys(\"sharding\");\n    }\n    \n    @Test\n    void assertGetLocalFailoverItems() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"sharding\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/failover\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/failover\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/2/failover\")).thenReturn(false);\n        when(jobNodeStorage.getJobNodeDataDirectly(\"sharding/0/failover\")).thenReturn(\"127.0.0.1@-@0\");\n        when(jobNodeStorage.getJobNodeDataDirectly(\"sharding/1/failover\")).thenReturn(\"127.0.0.1@-@1\");\n        assertThat(failoverService.getLocalFailoverItems(), is(Collections.singletonList(0)));\n        verify(jobNodeStorage).getJobNodeChildrenKeys(\"sharding\");\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/0/failover\");\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/1/failover\");\n        verify(jobNodeStorage).getJobNodeDataDirectly(\"sharding/0/failover\");\n        verify(jobNodeStorage).getJobNodeDataDirectly(\"sharding/1/failover\");\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertGetLocalTakeOffItems() {\n        when(shardingService.getLocalShardingItems()).thenReturn(Arrays.asList(0, 1, 2));\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/failover\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/failover\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/2/failover\")).thenReturn(false);\n        assertThat(failoverService.getLocalTakeOffItems(), is(Arrays.asList(0, 1)));\n        verify(shardingService).getLocalShardingItems();\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/0/failover\");\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/1/failover\");\n        verify(jobNodeStorage).isJobNodeExisted(\"sharding/2/failover\");\n    }\n    \n    @Test\n    void assertGetAllFailoveringItems() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).build());\n        String jobInstanceId = \"127.0.0.1@-@1\";\n        when(jobNodeStorage.getJobNodeData(\"sharding/0/failovering\")).thenReturn(jobInstanceId);\n        lenient().when(jobNodeStorage.getJobNodeData(\"sharding/2/failovering\")).thenReturn(jobInstanceId);\n        Map<Integer, JobInstance> actual = failoverService.getAllFailoveringItems();\n        assertThat(actual.size(), is(2));\n        assertThat(actual.get(0), is(new JobInstance(jobInstanceId)));\n        assertThat(actual.get(2), is(new JobInstance(jobInstanceId)));\n    }\n    \n    @Test\n    void assertClearFailoveringItem() {\n        failoverService.clearFailoveringItem(0);\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/0/failovering\");\n    }\n    \n    @Test\n    void assertRemoveFailoverInfo() {\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"sharding\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        failoverService.removeFailoverInfo();\n        verify(jobNodeStorage).getJobNodeChildrenKeys(\"sharding\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/0/failover\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/1/failover\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/2/failover\");\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/guarantee/GuaranteeListenerManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.guarantee;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.AbstractDistributeOnceElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass GuaranteeListenerManagerTest {\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private ElasticJobListener elasticJobListener;\n    \n    @Mock\n    private AbstractDistributeOnceElasticJobListener distributeOnceElasticJobListener;\n    \n    private GuaranteeListenerManager guaranteeListenerManager;\n    \n    @BeforeEach\n    void setUp() {\n        guaranteeListenerManager = new GuaranteeListenerManager(null, \"test_job\", Arrays.asList(elasticJobListener, distributeOnceElasticJobListener));\n        ReflectionUtils.setSuperclassFieldValue(guaranteeListenerManager, \"jobNodeStorage\", jobNodeStorage);\n    }\n    \n    @Test\n    void assertStart() {\n        guaranteeListenerManager.start();\n        verify(jobNodeStorage, times(2)).addDataListener(any(DataChangedEventListener.class));\n    }\n    \n    @Test\n    void assertStartedNodeRemovedJobListenerWhenIsNotRemoved() {\n        guaranteeListenerManager.new StartedNodeRemovedJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.UPDATED, \"/test_job/guarantee/started\", \"\"));\n        verify(distributeOnceElasticJobListener, times(0)).notifyWaitingTaskStart();\n    }\n    \n    @Test\n    void assertStartedNodeRemovedJobListenerWhenIsNotStartedNode() {\n        guaranteeListenerManager.new StartedNodeRemovedJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/other_job/guarantee/started\", \"\"));\n        verify(distributeOnceElasticJobListener, times(0)).notifyWaitingTaskStart();\n    }\n    \n    @Test\n    void assertStartedNodeRemovedJobListenerWhenIsRemovedAndStartedNode() {\n        guaranteeListenerManager.new StartedNodeRemovedJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/guarantee/started\", \"\"));\n        verify(distributeOnceElasticJobListener).notifyWaitingTaskStart();\n    }\n    \n    @Test\n    void assertCompletedNodeRemovedJobListenerWhenIsNotRemoved() {\n        guaranteeListenerManager.new CompletedNodeRemovedJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/guarantee/completed\", \"\"));\n        verify(distributeOnceElasticJobListener, times(0)).notifyWaitingTaskStart();\n    }\n    \n    @Test\n    void assertCompletedNodeRemovedJobListenerWhenIsNotCompletedNode() {\n        guaranteeListenerManager.new CompletedNodeRemovedJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/other_job/guarantee/completed\", \"\"));\n        verify(distributeOnceElasticJobListener, times(0)).notifyWaitingTaskStart();\n    }\n    \n    @Test\n    void assertCompletedNodeRemovedJobListenerWhenIsRemovedAndCompletedNode() {\n        guaranteeListenerManager.new CompletedNodeRemovedJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/guarantee/completed\", \"\"));\n        verify(distributeOnceElasticJobListener).notifyWaitingTaskComplete();\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/guarantee/GuaranteeNodeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.guarantee;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass GuaranteeNodeTest {\n    \n    private final GuaranteeNode guaranteeNode = new GuaranteeNode(\"test_job\");\n    \n    @Test\n    void assertGetStartedNode() {\n        assertThat(GuaranteeNode.getStartedNode(1), is(\"guarantee/started/1\"));\n    }\n    \n    @Test\n    void assertGetCompletedNode() {\n        assertThat(GuaranteeNode.getCompletedNode(1), is(\"guarantee/completed/1\"));\n    }\n    \n    @Test\n    void assertIsStartedRootNode() {\n        assertTrue(guaranteeNode.isStartedRootNode(\"/test_job/guarantee/started\"));\n    }\n    \n    @Test\n    void assertIsNotStartedRootNode() {\n        assertFalse(guaranteeNode.isStartedRootNode(\"/otherJob/guarantee/started\"));\n    }\n    \n    @Test\n    void assertIsCompletedRootNode() {\n        assertTrue(guaranteeNode.isCompletedRootNode(\"/test_job/guarantee/completed\"));\n    }\n    \n    @Test\n    void assertIsNotCompletedRootNode() {\n        assertFalse(guaranteeNode.isCompletedRootNode(\"/otherJob/guarantee/completed\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/guarantee/GuaranteeServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.guarantee;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.AbstractDistributeOnceElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass GuaranteeServiceTest {\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private ConfigurationService configService;\n    \n    @Mock\n    private AbstractDistributeOnceElasticJobListener listener;\n    \n    @Mock\n    private ShardingContexts shardingContexts;\n    \n    private final GuaranteeService guaranteeService = new GuaranteeService(null, \"test_job\");\n    \n    @BeforeEach\n    void setUp() {\n        ReflectionUtils.setFieldValue(guaranteeService, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(guaranteeService, \"configService\", configService);\n    }\n    \n    @Test\n    void assertRegisterStart() {\n        guaranteeService.registerStart(Arrays.asList(0, 1));\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"guarantee/started/0\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"guarantee/started/1\");\n    }\n    \n    @Test\n    void assertIsNotRegisterStartSuccess() {\n        assertFalse(guaranteeService.isRegisterStartSuccess(Arrays.asList(0, 1)));\n    }\n    \n    @Test\n    void assertIsRegisterStartSuccess() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/started/0\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/started/1\")).thenReturn(true);\n        assertTrue(guaranteeService.isRegisterStartSuccess(Arrays.asList(0, 1)));\n    }\n    \n    @Test\n    void assertIsNotAllStartedWhenRootNodeIsNotExisted() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/started\")).thenReturn(false);\n        assertFalse(guaranteeService.isAllStarted());\n    }\n    \n    @Test\n    void assertIsNotAllStarted() {\n        when(configService.load(false)).thenReturn(\n                JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").setProperty(\"streaming.process\", Boolean.TRUE.toString()).build());\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/started\")).thenReturn(true);\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"guarantee/started\")).thenReturn(Arrays.asList(\"0\", \"1\"));\n        assertFalse(guaranteeService.isAllStarted());\n    }\n    \n    @Test\n    void assertIsAllStarted() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/started\")).thenReturn(true);\n        when(configService.load(false)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"guarantee/started\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        assertTrue(guaranteeService.isAllStarted());\n    }\n    \n    @Test\n    void assertClearAllStartedInfo() {\n        guaranteeService.clearAllStartedInfo();\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"guarantee/started\");\n    }\n    \n    @Test\n    void assertRegisterComplete() {\n        guaranteeService.registerComplete(Arrays.asList(0, 1));\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"guarantee/completed/0\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"guarantee/completed/1\");\n    }\n    \n    @Test\n    void assertIsNotRegisterCompleteSuccess() {\n        assertFalse(guaranteeService.isRegisterCompleteSuccess(Arrays.asList(0, 1)));\n    }\n    \n    @Test\n    void assertIsRegisterCompleteSuccess() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/completed/0\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/completed/1\")).thenReturn(true);\n        assertTrue(guaranteeService.isRegisterCompleteSuccess(Arrays.asList(0, 1)));\n    }\n    \n    @Test\n    void assertIsNotAllCompletedWhenRootNodeIsNotExisted() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/completed\")).thenReturn(false);\n        assertFalse(guaranteeService.isAllCompleted());\n    }\n    \n    @Test\n    void assertIsNotAllCompleted() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/completed\")).thenReturn(false);\n        assertFalse(guaranteeService.isAllCompleted());\n    }\n    \n    @Test\n    void assertIsAllCompleted() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/completed\")).thenReturn(true);\n        when(configService.load(false)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"guarantee/completed\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        assertTrue(guaranteeService.isAllCompleted());\n    }\n    \n    @Test\n    void assertClearAllCompletedInfo() {\n        guaranteeService.clearAllCompletedInfo();\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"guarantee/completed\");\n    }\n    \n    @Test\n    void assertExecuteInLeaderForLastCompleted() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/completed\")).thenReturn(true);\n        when(configService.load(false)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"guarantee/completed\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        guaranteeService.new LeaderExecutionCallbackForLastCompleted(listener, shardingContexts).execute();\n        verify(listener).doAfterJobExecutedAtLastCompleted(shardingContexts);\n    }\n    \n    @Test\n    void assertExecuteInLeaderForNotLastCompleted() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/completed\")).thenReturn(false);\n        guaranteeService.new LeaderExecutionCallbackForLastCompleted(listener, shardingContexts).execute();\n        verify(listener, never()).doAfterJobExecutedAtLastCompleted(shardingContexts);\n    }\n    \n    @Test\n    void assertExecuteInLeaderForLastStarted() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/started\")).thenReturn(true);\n        when(configService.load(false)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"guarantee/started\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        guaranteeService.new LeaderExecutionCallbackForLastStarted(listener, shardingContexts).execute();\n        verify(listener).doBeforeJobExecutedAtLastStarted(shardingContexts);\n    }\n    \n    @Test\n    void assertExecuteInLeaderForNotLastStarted() {\n        when(jobNodeStorage.isJobNodeExisted(\"guarantee/started\")).thenReturn(false);\n        guaranteeService.new LeaderExecutionCallbackForLastStarted(listener, shardingContexts).execute();\n        verify(listener, never()).doBeforeJobExecutedAtLastStarted(shardingContexts);\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/instance/InstanceNodeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.instance;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass InstanceNodeTest {\n    \n    private static InstanceNode instanceNode;\n    \n    @BeforeAll\n    static void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        instanceNode = new InstanceNode(\"test_job\");\n    }\n    \n    @Test\n    void assertGetInstanceFullPath() {\n        assertThat(instanceNode.getInstanceFullPath(), is(\"/test_job/instances\"));\n    }\n    \n    @Test\n    void assertIsInstancePath() {\n        assertTrue(instanceNode.isInstancePath(\"/test_job/instances/127.0.0.1@-@0\"));\n    }\n    \n    @Test\n    void assertIsNotInstancePath() {\n        assertFalse(instanceNode.isInstancePath(\"/test_job/other/127.0.0.1@-@0\"));\n    }\n    \n    @Test\n    void assertIsLocalInstancePath() {\n        assertTrue(instanceNode.isLocalInstancePath(\"/test_job/instances/127.0.0.1@-@0\"));\n    }\n    \n    @Test\n    void assertIsNotLocalInstancePath() {\n        assertFalse(instanceNode.isLocalInstancePath(\"/test_job/instances/127.0.0.2@-@0\"));\n    }\n    \n    @Test\n    void assertGetLocalInstancePath() {\n        assertThat(instanceNode.getLocalInstancePath(), is(\"instances/127.0.0.1@-@0\"));\n    }\n    \n    @Test\n    void assertGetInstancePath() {\n        assertThat(instanceNode.getInstancePath(\"127.0.0.1@-@0\"), is(\"instances/127.0.0.1@-@0\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/instance/InstanceServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.instance;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass InstanceServiceTest {\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private ServerService serverService;\n    \n    private InstanceService instanceService;\n    \n    @BeforeEach\n    void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\", null, \"127.0.0.1\"));\n        instanceService = new InstanceService(null, \"test_job\");\n        InstanceNode instanceNode = new InstanceNode(\"test_job\");\n        ReflectionUtils.setFieldValue(instanceService, \"instanceNode\", instanceNode);\n        ReflectionUtils.setFieldValue(instanceService, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(instanceService, \"serverService\", serverService);\n    }\n    \n    @Test\n    void assertPersistOnline() {\n        instanceService.persistOnline();\n        verify(jobNodeStorage).fillEphemeralJobNode(\"instances/127.0.0.1@-@0\", \"jobInstanceId: 127.0.0.1@-@0\\nserverIp: 127.0.0.1\\n\");\n    }\n    \n    @Test\n    void assertRemoveInstance() {\n        instanceService.removeInstance();\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"instances/127.0.0.1@-@0\");\n    }\n    \n    @Test\n    void assertGetAvailableJobInstances() {\n        when(jobNodeStorage.getJobNodeChildrenKeys(InstanceNode.ROOT)).thenReturn(Arrays.asList(\"127.0.0.1@-@0\", \"127.0.0.2@-@0\"));\n        when(jobNodeStorage.getJobNodeData(\"instances/127.0.0.1@-@0\")).thenReturn(\"jobInstanceId: 127.0.0.1@-@0\\nlabels: labels\\nserverIp: 127.0.0.1\\n\");\n        when(jobNodeStorage.getJobNodeData(\"instances/127.0.0.2@-@0\")).thenReturn(\"jobInstanceId: 127.0.0.2@-@0\\nlabels: labels\\nserverIp: 127.0.0.2\\n\");\n        when(serverService.isEnableServer(\"127.0.0.1\")).thenReturn(true);\n        assertThat(instanceService.getAvailableJobInstances(), is(Collections.singletonList(new JobInstance(\"127.0.0.1@-@0\"))));\n    }\n    \n    @Test\n    void assertGetAvailableJobInstancesWhenInstanceRemoving() {\n        when(jobNodeStorage.getJobNodeChildrenKeys(InstanceNode.ROOT)).thenReturn(Arrays.asList(\"127.0.0.1@-@0\", \"127.0.0.2@-@0\"));\n        when(jobNodeStorage.getJobNodeData(\"instances/127.0.0.1@-@0\")).thenReturn(\"jobInstanceId: 127.0.0.1@-@0\\nlabels: labels\\nserverIp: 127.0.0.1\\n\");\n        when(serverService.isEnableServer(\"127.0.0.1\")).thenReturn(true);\n        assertThat(instanceService.getAvailableJobInstances(), is(Collections.singletonList(new JobInstance(\"127.0.0.1@-@0\"))));\n    }\n    \n    @Test\n    void assertIsLocalJobInstanceExisted() {\n        when(jobNodeStorage.isJobNodeExisted(\"instances/127.0.0.1@-@0\")).thenReturn(true);\n        assertTrue(instanceService.isLocalJobInstanceExisted());\n    }\n    \n    @Test\n    void assertTriggerAllInstances() {\n        when(jobNodeStorage.getJobNodeChildrenKeys(InstanceNode.ROOT)).thenReturn(Arrays.asList(\"127.0.0.1@-@0\", \"127.0.0.2@-@0\"));\n        instanceService.triggerAllInstances();\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"trigger/127.0.0.1@-@0\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"trigger/127.0.0.2@-@0\");\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/instance/ShutdownListenerManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.instance;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.SchedulerFacade;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ShutdownListenerManagerTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private InstanceService instanceService;\n    \n    @Mock\n    private SchedulerFacade schedulerFacade;\n    \n    private ShutdownListenerManager shutdownListenerManager;\n    \n    @BeforeEach\n    void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        shutdownListenerManager = new ShutdownListenerManager(null, \"test_job\");\n        ReflectionUtils.setFieldValue(shutdownListenerManager, \"instanceService\", instanceService);\n        ReflectionUtils.setFieldValue(shutdownListenerManager, \"schedulerFacade\", schedulerFacade);\n        ReflectionUtils.setSuperclassFieldValue(shutdownListenerManager, \"jobNodeStorage\", jobNodeStorage);\n    }\n    \n    @AfterEach\n    void tearDown() {\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertStart() {\n        shutdownListenerManager.start();\n        verify(jobNodeStorage).addDataListener(ArgumentMatchers.any());\n    }\n    \n    @Test\n    void assertIsShutdownAlready() {\n        shutdownListenerManager.new InstanceShutdownStatusJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/instances/127.0.0.1@-@0\", \"\"));\n        verify(schedulerFacade, times(0)).shutdownInstance();\n    }\n    \n    @Test\n    void assertIsNotLocalInstancePath() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        shutdownListenerManager.new InstanceShutdownStatusJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/instances/127.0.0.2@-@0\", \"\"));\n        verify(schedulerFacade, times(0)).shutdownInstance();\n    }\n    \n    @Test\n    void assertUpdateLocalInstancePath() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        shutdownListenerManager.new InstanceShutdownStatusJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/instances/127.0.0.1@-@0\", \"\"));\n        verify(schedulerFacade, times(0)).shutdownInstance();\n    }\n    \n    @Test\n    void assertRemoveLocalInstancePathForPausedJob() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(jobScheduleController.isPaused()).thenReturn(true);\n        shutdownListenerManager.new InstanceShutdownStatusJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/instances/127.0.0.1@-@0\", \"\"));\n        verify(schedulerFacade, times(0)).shutdownInstance();\n    }\n    \n    @Test\n    void assertRemoveLocalInstancePathForReconnectedRegistryCenter() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(instanceService.isLocalJobInstanceExisted()).thenReturn(true);\n        shutdownListenerManager.new InstanceShutdownStatusJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/instances/127.0.0.1@-@0\", \"\"));\n        verify(schedulerFacade, times(0)).shutdownInstance();\n    }\n    \n    @Test\n    void assertRemoveLocalInstancePath() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        shutdownListenerManager.new InstanceShutdownStatusJobListener().onChange(new DataChangedEvent(Type.DELETED, \"/test_job/instances/127.0.0.1@-@0\", \"\"));\n        verify(schedulerFacade).shutdownInstance();\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/listener/ListenerManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.listener;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.RescheduleListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.ElectionListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.guarantee.GuaranteeListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.ShutdownListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.MonitorExecutionListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.trigger.TriggerListenerManager;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Collections;\n\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass ListenerManagerTest {\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private ElectionListenerManager electionListenerManager;\n    \n    @Mock\n    private ShardingListenerManager shardingListenerManager;\n    \n    @Mock\n    private FailoverListenerManager failoverListenerManager;\n    \n    @Mock\n    private MonitorExecutionListenerManager monitorExecutionListenerManager;\n    \n    @Mock\n    private ShutdownListenerManager shutdownListenerManager;\n    \n    @Mock\n    private TriggerListenerManager triggerListenerManager;\n    \n    @Mock\n    private RescheduleListenerManager rescheduleListenerManager;\n    \n    @Mock\n    private GuaranteeListenerManager guaranteeListenerManager;\n    \n    @Mock\n    private RegistryCenterConnectionStateListener regCenterConnectionStateListener;\n    \n    private final ListenerManager listenerManager = new ListenerManager(null, \"test_job\", Collections.emptyList());\n    \n    @BeforeEach\n    void setUp() {\n        ReflectionUtils.setFieldValue(listenerManager, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(listenerManager, \"electionListenerManager\", electionListenerManager);\n        ReflectionUtils.setFieldValue(listenerManager, \"shardingListenerManager\", shardingListenerManager);\n        ReflectionUtils.setFieldValue(listenerManager, \"failoverListenerManager\", failoverListenerManager);\n        ReflectionUtils.setFieldValue(listenerManager, \"monitorExecutionListenerManager\", monitorExecutionListenerManager);\n        ReflectionUtils.setFieldValue(listenerManager, \"shutdownListenerManager\", shutdownListenerManager);\n        ReflectionUtils.setFieldValue(listenerManager, \"triggerListenerManager\", triggerListenerManager);\n        ReflectionUtils.setFieldValue(listenerManager, \"rescheduleListenerManager\", rescheduleListenerManager);\n        ReflectionUtils.setFieldValue(listenerManager, \"guaranteeListenerManager\", guaranteeListenerManager);\n        ReflectionUtils.setFieldValue(listenerManager, \"regCenterConnectionStateListener\", regCenterConnectionStateListener);\n    }\n    \n    @Test\n    void assertStartAllListeners() {\n        listenerManager.startAllListeners();\n        verify(electionListenerManager).start();\n        verify(shardingListenerManager).start();\n        verify(failoverListenerManager).start();\n        verify(monitorExecutionListenerManager).start();\n        verify(shutdownListenerManager).start();\n        verify(rescheduleListenerManager).start();\n        verify(guaranteeListenerManager).start();\n        verify(jobNodeStorage).addConnectionStateListener(regCenterConnectionStateListener);\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/listener/ListenerNotifierManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.listener;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.concurrent.Executor;\n\nimport static org.hamcrest.CoreMatchers.notNullValue;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@ExtendWith(MockitoExtension.class)\nclass ListenerNotifierManagerTest {\n    \n    @Test\n    void assertRegisterAndGetJobNotifyExecutor() {\n        String jobName = \"test_job\";\n        ListenerNotifierManager.getInstance().registerJobNotifyExecutor(jobName);\n        assertThat(ListenerNotifierManager.getInstance().getJobNotifyExecutor(jobName), notNullValue(Executor.class));\n    }\n    \n    @Test\n    void assertRemoveAndShutDownJobNotifyExecutor() {\n        String jobName = \"test_job\";\n        ListenerNotifierManager.getInstance().registerJobNotifyExecutor(jobName);\n        ListenerNotifierManager.getInstance().removeJobNotifyExecutor(jobName);\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/listener/RegistryCenterConnectionStateListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.listener;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.ConnectionStateChangedEventListener.State;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\n\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass RegistryCenterConnectionStateListenerTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private ServerService serverService;\n    \n    @Mock\n    private InstanceService instanceService;\n    \n    @Mock\n    private ShardingService shardingService;\n    \n    @Mock\n    private ExecutionService executionService;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    private RegistryCenterConnectionStateListener regCenterConnectionStateListener;\n    \n    @BeforeEach\n    void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\", null, \"127.0.0.1\"));\n        regCenterConnectionStateListener = new RegistryCenterConnectionStateListener(null, \"test_job\");\n        ReflectionUtils.setFieldValue(regCenterConnectionStateListener, \"serverService\", serverService);\n        ReflectionUtils.setFieldValue(regCenterConnectionStateListener, \"instanceService\", instanceService);\n        ReflectionUtils.setFieldValue(regCenterConnectionStateListener, \"shardingService\", shardingService);\n        ReflectionUtils.setFieldValue(regCenterConnectionStateListener, \"executionService\", executionService);\n    }\n    \n    @Test\n    void assertConnectionLostListenerWhenConnectionStateIsLost() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        regCenterConnectionStateListener.onStateChanged(null, State.UNAVAILABLE);\n        verify(jobScheduleController).pauseJob();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertConnectionLostListenerWhenConnectionStateIsLostButIsShutdown() {\n        regCenterConnectionStateListener.onStateChanged(null, State.UNAVAILABLE);\n        verify(jobScheduleController, times(0)).pauseJob();\n        verify(jobScheduleController, times(0)).resumeJob();\n    }\n    \n    @Test\n    void assertConnectionLostListenerWhenConnectionStateIsReconnected() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(shardingService.getLocalShardingItems()).thenReturn(Arrays.asList(0, 1));\n        when(serverService.isEnableServer(\"127.0.0.1\")).thenReturn(true);\n        regCenterConnectionStateListener.onStateChanged(null, State.RECONNECTED);\n        verify(serverService).persistOnline(true);\n        verify(executionService).clearRunningInfo(Arrays.asList(0, 1));\n        verify(jobScheduleController).resumeJob();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertConnectionLostListenerWhenConnectionStateIsReconnectedButIsShutdown() {\n        regCenterConnectionStateListener.onStateChanged(null, State.RECONNECTED);\n        verify(jobScheduleController, times(0)).pauseJob();\n        verify(jobScheduleController, times(0)).resumeJob();\n    }\n    \n    @Test\n    void assertConnectionLostListenerWhenConnectionStateIsOther() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        regCenterConnectionStateListener.onStateChanged(null, State.CONNECTED);\n        verify(jobScheduleController, times(0)).pauseJob();\n        verify(jobScheduleController, times(0)).resumeJob();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/reconcile/ReconcileServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.reconcile;\n\nimport com.google.common.collect.Lists;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ReconcileServiceTest {\n    \n    @Mock\n    private ConfigurationService configService;\n    \n    @Mock\n    private ShardingService shardingService;\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    private ReconcileService reconcileService;\n    \n    @BeforeEach\n    void setup() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        reconcileService = new ReconcileService(regCenter, \"test_job\");\n        ReflectionUtils.setFieldValue(reconcileService, \"lastReconcileTime\", 1L);\n        ReflectionUtils.setFieldValue(reconcileService, \"configService\", configService);\n        ReflectionUtils.setFieldValue(reconcileService, \"shardingService\", shardingService);\n    }\n    \n    @Test\n    void assertReconcile() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").reconcileIntervalMinutes(1).build());\n        when(shardingService.isNeedSharding()).thenReturn(false);\n        when(shardingService.hasShardingInfoInOfflineServers()).thenReturn(true);\n        reconcileService.runOneIteration();\n        verify(shardingService).isNeedSharding();\n        verify(shardingService).hasShardingInfoInOfflineServers();\n        verify(shardingService).setReshardingFlag();\n    }\n    \n    @Test\n    void assertReconcileWithStaticSharding() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").reconcileIntervalMinutes(1).staticSharding(true).build());\n        when(shardingService.isNeedSharding()).thenReturn(false);\n        when(shardingService.hasShardingInfoInOfflineServers()).thenReturn(true);\n        when(regCenter.getChildrenKeys(\"/test_job/sharding\")).thenReturn(Lists.newArrayList(\"0\"));\n        reconcileService.runOneIteration();\n        verify(shardingService).isNeedSharding();\n        verify(shardingService).hasShardingInfoInOfflineServers();\n        verify(shardingService, times(0)).setReshardingFlag();\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/JobRegistryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\n\nclass JobRegistryTest {\n    \n    @Test\n    void assertRegisterJob() {\n        JobScheduleController jobScheduleController = mock(JobScheduleController.class);\n        JobRegistry.getInstance().registerJob(\"test_job_scheduler_for_add\", jobScheduleController);\n        assertThat(JobRegistry.getInstance().getJobScheduleController(\"test_job_scheduler_for_add\"), is(jobScheduleController));\n    }\n    \n    @Test\n    void assertGetJobInstance() {\n        JobRegistry.getInstance().addJobInstance(\"exist_job_instance\", new JobInstance(\"127.0.0.1@-@0\"));\n        assertThat(JobRegistry.getInstance().getJobInstance(\"exist_job_instance\"), is(new JobInstance(\"127.0.0.1@-@0\")));\n    }\n    \n    @Test\n    void assertGetRegCenter() {\n        CoordinatorRegistryCenter regCenter = mock(CoordinatorRegistryCenter.class);\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job_scheduler_for_add\", regCenter);\n        assertThat(JobRegistry.getInstance().getRegCenter(\"test_job_scheduler_for_add\"), is(regCenter));\n    }\n    \n    @Test\n    void assertIsJobRunningIfNull() {\n        assertFalse(JobRegistry.getInstance().isJobRunning(\"null_job_instance\"));\n    }\n    \n    @Test\n    void assertIsJobRunningIfNotNull() {\n        JobRegistry.getInstance().setJobRunning(\"exist_job_instance\", true);\n        assertTrue(JobRegistry.getInstance().isJobRunning(\"exist_job_instance\"));\n    }\n    \n    @Test\n    void assertGetCurrentShardingTotalCountIfNull() {\n        assertThat(JobRegistry.getInstance().getCurrentShardingTotalCount(\"exist_job_instance\"), is(0));\n    }\n    \n    @Test\n    void assertGetCurrentShardingTotalCountIfNotNull() {\n        JobRegistry.getInstance().setCurrentShardingTotalCount(\"exist_job_instance\", 10);\n        assertThat(JobRegistry.getInstance().getCurrentShardingTotalCount(\"exist_job_instance\"), is(10));\n        ReflectionUtils.setFieldValue(JobRegistry.getInstance(), \"instance\", null);\n    }\n    \n    @Test\n    void assertShutdown() {\n        JobScheduleController jobScheduleController = mock(JobScheduleController.class);\n        CoordinatorRegistryCenter regCenter = mock(CoordinatorRegistryCenter.class);\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job_for_shutdown\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job_for_shutdown\", jobScheduleController);\n        JobRegistry.getInstance().shutdown(\"test_job_for_shutdown\");\n        verify(jobScheduleController).shutdown();\n        verify(regCenter).evictCacheData(\"/test_job_for_shutdown\");\n    }\n    \n    @Test\n    void assertIsShutdownForJobSchedulerNull() {\n        assertTrue(JobRegistry.getInstance().isShutdown(\"test_job_for_job_scheduler_null\"));\n    }\n    \n    @Test\n    void assertIsShutdownForJobInstanceNull() {\n        JobScheduleController jobScheduleController = mock(JobScheduleController.class);\n        CoordinatorRegistryCenter regCenter = mock(CoordinatorRegistryCenter.class);\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job_for_job_instance_null\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job_for_job_instance_null\", jobScheduleController);\n        assertTrue(JobRegistry.getInstance().isShutdown(\"test_job_for_job_instance_null\"));\n    }\n    \n    @Test\n    void assertIsNotShutdown() {\n        JobScheduleController jobScheduleController = mock(JobScheduleController.class);\n        CoordinatorRegistryCenter regCenter = mock(CoordinatorRegistryCenter.class);\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job_for_job_not_shutdown\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job_for_job_not_shutdown\", jobScheduleController);\n        JobRegistry.getInstance().addJobInstance(\"test_job_for_job_not_shutdown\", new JobInstance(\"127.0.0.1@-@0\"));\n        assertFalse(JobRegistry.getInstance().isShutdown(\"test_job_for_job_not_shutdown\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/JobScheduleControllerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport org.quartz.JobDetail;\nimport org.quartz.JobKey;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.quartz.Trigger;\nimport org.quartz.TriggerKey;\nimport org.quartz.impl.triggers.CronTriggerImpl;\nimport org.quartz.impl.triggers.SimpleTriggerImpl;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass JobScheduleControllerTest {\n    \n    @Mock\n    private Scheduler scheduler;\n    \n    @Mock\n    private JobDetail jobDetail;\n    \n    private JobScheduleController jobScheduleController;\n    \n    @BeforeEach\n    void setUp() {\n        jobScheduleController = new JobScheduleController(scheduler, jobDetail, \"test_job_Trigger\");\n    }\n    \n    @Test\n    void assertIsPausedFailure() {\n        assertThrows(JobSystemException.class, () -> {\n            doThrow(SchedulerException.class).when(scheduler).getTriggerState(new TriggerKey(\"test_job_Trigger\"));\n            ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n            try {\n                jobScheduleController.isPaused();\n            } finally {\n                verify(scheduler).getTriggerState(new TriggerKey(\"test_job_Trigger\"));\n            }\n        });\n    }\n    \n    @Test\n    void assertIsPausedIfTriggerStateIsNormal() throws SchedulerException {\n        when(scheduler.getTriggerState(new TriggerKey(\"test_job_Trigger\"))).thenReturn(Trigger.TriggerState.NORMAL);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        assertFalse(jobScheduleController.isPaused());\n    }\n    \n    @Test\n    void assertIsPausedIfTriggerStateIsPaused() throws SchedulerException {\n        when(scheduler.getTriggerState(new TriggerKey(\"test_job_Trigger\"))).thenReturn(Trigger.TriggerState.PAUSED);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        assertTrue(jobScheduleController.isPaused());\n    }\n    \n    @Test\n    void assertIsPauseJobIfShutdown() throws SchedulerException {\n        when(scheduler.isShutdown()).thenReturn(true);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        assertFalse(jobScheduleController.isPaused());\n    }\n    \n    @Test\n    void assertPauseJobIfShutdown() throws SchedulerException {\n        when(scheduler.isShutdown()).thenReturn(true);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        jobScheduleController.pauseJob();\n        verify(scheduler, times(0)).pauseAll();\n    }\n    \n    @Test\n    void assertPauseJobFailure() {\n        assertThrows(JobSystemException.class, () -> {\n            doThrow(SchedulerException.class).when(scheduler).pauseAll();\n            ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n            try {\n                jobScheduleController.pauseJob();\n            } finally {\n                verify(scheduler).pauseAll();\n            }\n        });\n    }\n    \n    @Test\n    void assertPauseJobSuccess() throws SchedulerException {\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        jobScheduleController.pauseJob();\n        verify(scheduler).pauseAll();\n    }\n    \n    @Test\n    void assertResumeJobIfShutdown() throws SchedulerException {\n        when(scheduler.isShutdown()).thenReturn(true);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        jobScheduleController.resumeJob();\n        verify(scheduler, times(0)).resumeAll();\n    }\n    \n    @Test\n    void assertResumeJobFailure() {\n        assertThrows(JobSystemException.class, () -> {\n            doThrow(SchedulerException.class).when(scheduler).resumeAll();\n            ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n            try {\n                jobScheduleController.resumeJob();\n            } finally {\n                verify(scheduler).resumeAll();\n            }\n        });\n    }\n    \n    @Test\n    void assertResumeJobSuccess() throws SchedulerException {\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        jobScheduleController.resumeJob();\n        verify(scheduler).resumeAll();\n    }\n    \n    @Test\n    void assertTriggerJobIfShutdown() throws SchedulerException {\n        when(scheduler.isShutdown()).thenReturn(true);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"jobDetail\", jobDetail);\n        jobScheduleController.triggerJob();\n        verify(jobDetail, times(0)).getKey();\n        verify(scheduler, times(0)).triggerJob(any());\n    }\n    \n    @Test\n    void assertTriggerJobFailure() {\n        assertThrows(JobSystemException.class, () -> {\n            JobKey jobKey = new JobKey(\"test_job\");\n            when(jobDetail.getKey()).thenReturn(jobKey);\n            when(scheduler.checkExists(jobKey)).thenReturn(true);\n            doThrow(SchedulerException.class).when(scheduler).triggerJob(jobKey);\n            ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n            ReflectionUtils.setFieldValue(jobScheduleController, \"jobDetail\", jobDetail);\n            try {\n                jobScheduleController.triggerJob();\n            } finally {\n                verify(jobDetail, times(2)).getKey();\n                verify(scheduler).triggerJob(jobKey);\n            }\n        });\n    }\n    \n    @Test\n    void assertTriggerJobSuccess() throws SchedulerException {\n        JobKey jobKey = new JobKey(\"test_job\");\n        when(jobDetail.getKey()).thenReturn(jobKey);\n        when(scheduler.checkExists(any(JobKey.class))).thenReturn(true);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"jobDetail\", jobDetail);\n        jobScheduleController.triggerJob();\n        verify(jobDetail, times(2)).getKey();\n        verify(scheduler).triggerJob(jobKey);\n    }\n    \n    @Test\n    void assertTriggerOneOffJobSuccess() throws SchedulerException {\n        JobKey jobKey = new JobKey(\"test_job\");\n        when(jobDetail.getKey()).thenReturn(jobKey);\n        when(scheduler.checkExists(jobDetail.getKey())).thenReturn(false);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        ReflectionUtils.setFieldValue(jobScheduleController, \"jobDetail\", jobDetail);\n        jobScheduleController.triggerJob();\n        verify(jobDetail, times(2)).getKey();\n        verify(scheduler).scheduleJob(eq(jobDetail), any(Trigger.class));\n        verify(scheduler).start();\n    }\n    \n    @Test\n    void assertShutdownJobIfShutdown() throws SchedulerException {\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        when(scheduler.isShutdown()).thenReturn(true);\n        jobScheduleController.shutdown();\n        verify(scheduler, times(0)).shutdown();\n    }\n    \n    @Test\n    void assertShutdownFailure() {\n        assertThrows(JobSystemException.class, () -> {\n            doThrow(SchedulerException.class).when(scheduler).shutdown(false);\n            ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n            try {\n                jobScheduleController.shutdown();\n            } finally {\n                verify(scheduler).shutdown(false);\n            }\n        });\n    }\n    \n    @Test\n    void assertShutdownSuccess() throws SchedulerException {\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        jobScheduleController.shutdown();\n        verify(scheduler).shutdown(false);\n    }\n    \n    @Test\n    void assertRescheduleJobIfShutdown() throws SchedulerException {\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        when(scheduler.isShutdown()).thenReturn(true);\n        jobScheduleController.rescheduleJob(\"0/1 * * * * ?\", null);\n        verify(scheduler, times(0)).rescheduleJob(eq(TriggerKey.triggerKey(\"test_job_Trigger\")), any());\n    }\n    \n    @Test\n    void assertRescheduleJobFailure() {\n        assertThrows(JobSystemException.class, () -> {\n            when(scheduler.getTrigger(TriggerKey.triggerKey(\"test_job_Trigger\"))).thenReturn(new CronTriggerImpl());\n            doThrow(SchedulerException.class).when(scheduler).rescheduleJob(eq(TriggerKey.triggerKey(\"test_job_Trigger\")), any());\n            ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n            try {\n                jobScheduleController.rescheduleJob(\"0/1 * * * * ?\", null);\n            } finally {\n                verify(scheduler).rescheduleJob(eq(TriggerKey.triggerKey(\"test_job_Trigger\")), any());\n            }\n        });\n    }\n    \n    @Test\n    void assertRescheduleJobSuccess() throws SchedulerException {\n        when(scheduler.getTrigger(TriggerKey.triggerKey(\"test_job_Trigger\"))).thenReturn(new CronTriggerImpl());\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        jobScheduleController.rescheduleJob(\"0/1 * * * * ?\", null);\n        verify(scheduler).rescheduleJob(eq(TriggerKey.triggerKey(\"test_job_Trigger\")), any());\n    }\n    \n    @Test\n    void assertRescheduleJobWhenTriggerIsNull() throws SchedulerException {\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        jobScheduleController.rescheduleJob(\"0/1 * * * * ?\", null);\n        verify(scheduler, times(0)).rescheduleJob(eq(TriggerKey.triggerKey(\"test_job_Trigger\")), any());\n    }\n    \n    @Test\n    void assertRescheduleJobIfShutdownForOneOffJob() throws SchedulerException {\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        when(scheduler.isShutdown()).thenReturn(true);\n        jobScheduleController.rescheduleJob();\n        verify(scheduler, times(0)).rescheduleJob(eq(TriggerKey.triggerKey(\"test_job_Trigger\")), any());\n    }\n    \n    @Test\n    void assertRescheduleJobFailureForOneOffJob() {\n        assertThrows(JobSystemException.class, () -> {\n            when(scheduler.getTrigger(TriggerKey.triggerKey(\"test_job_Trigger\"))).thenReturn(new SimpleTriggerImpl());\n            doThrow(SchedulerException.class).when(scheduler).rescheduleJob(eq(TriggerKey.triggerKey(\"test_job_Trigger\")), any());\n            ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n            try {\n                jobScheduleController.rescheduleJob();\n            } finally {\n                verify(scheduler).rescheduleJob(eq(TriggerKey.triggerKey(\"test_job_Trigger\")), any());\n            }\n        });\n    }\n    \n    @Test\n    void assertRescheduleJobSuccessForOneOffJob() throws SchedulerException {\n        when(scheduler.getTrigger(TriggerKey.triggerKey(\"test_job_Trigger\"))).thenReturn(new SimpleTriggerImpl());\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        jobScheduleController.rescheduleJob();\n        verify(scheduler).rescheduleJob(eq(TriggerKey.triggerKey(\"test_job_Trigger\")), any());\n    }\n    \n    @Test\n    void assertRescheduleJobWhenTriggerIsNullForOneOffJob() throws SchedulerException {\n        ReflectionUtils.setFieldValue(jobScheduleController, \"scheduler\", scheduler);\n        jobScheduleController.rescheduleJob();\n        verify(scheduler, times(0)).rescheduleJob(eq(TriggerKey.triggerKey(\"test_job_Trigger\")), any());\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/JobTriggerListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport org.quartz.Trigger;\n\nimport java.util.Collections;\nimport java.util.Date;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass JobTriggerListenerTest {\n    \n    @Mock\n    private ExecutionService executionService;\n    \n    @Mock\n    private ShardingService shardingService;\n    \n    @Mock\n    private Trigger trigger;\n    \n    private JobTriggerListener jobTriggerListener;\n    \n    @BeforeEach\n    void setUp() {\n        jobTriggerListener = new JobTriggerListener(executionService, shardingService);\n    }\n    \n    @Test\n    void assertGetName() {\n        assertThat(jobTriggerListener.getName(), is(\"JobTriggerListener\"));\n    }\n    \n    @Test\n    void assertTriggerMisfiredWhenPreviousFireTimeIsNull() {\n        jobTriggerListener.triggerMisfired(trigger);\n        verify(executionService, times(0)).setMisfire(Collections.singletonList(0));\n    }\n    \n    @Test\n    void assertTriggerMisfiredWhenPreviousFireTimeIsNotNull() {\n        when(shardingService.getLocalShardingItems()).thenReturn(Collections.singletonList(0));\n        when(trigger.getPreviousFireTime()).thenReturn(new Date());\n        jobTriggerListener.triggerMisfired(trigger);\n        verify(executionService).setMisfire(Collections.singletonList(0));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/schedule/SchedulerFacadeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.schedule;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass SchedulerFacadeTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    @Mock\n    private LeaderService leaderService;\n    \n    @Mock\n    private ShardingService shardingService;\n    \n    private SchedulerFacade schedulerFacade;\n    \n    @BeforeEach\n    void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        schedulerFacade = new SchedulerFacade(null, \"test_job\");\n        ReflectionUtils.setFieldValue(schedulerFacade, \"leaderService\", leaderService);\n        ReflectionUtils.setFieldValue(schedulerFacade, \"shardingService\", shardingService);\n    }\n    \n    @Test\n    void assertShutdownInstanceIfNotLeaderAndReconcileServiceIsNotRunning() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        schedulerFacade.shutdownInstance();\n        verify(leaderService, times(0)).removeLeader();\n        verify(jobScheduleController).shutdown();\n    }\n    \n    @Test\n    void assertShutdownInstanceIfLeaderAndReconcileServiceIsRunning() {\n        when(leaderService.isLeader()).thenReturn(true);\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        schedulerFacade.shutdownInstance();\n        verify(leaderService).removeLeader();\n        verify(jobScheduleController).shutdown();\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/server/ServerNodeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.server;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ServerNodeTest {\n    \n    private final ServerNode serverNode = new ServerNode(\"test_job\");\n    \n    @BeforeAll\n    static void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\", null, \"127.0.0.1\"));\n    }\n    \n    @Test\n    void assertIsServerPath() {\n        assertTrue(serverNode.isServerPath(\"/test_job/servers/127.0.0.1\"));\n    }\n    \n    @Test\n    void assertIsNotServerPath() {\n        assertFalse(serverNode.isServerPath(\"/test_job/servers/255.255.255.256\"));\n    }\n    \n    @Test\n    void assertIsLocalServerPath() {\n        assertTrue(serverNode.isLocalServerPath(\"/test_job/servers/127.0.0.1\"));\n    }\n    \n    @Test\n    void assertIsNotLocalServerPath() {\n        assertFalse(serverNode.isLocalServerPath(\"/test_job/servers/127.0.0.2\"));\n    }\n    \n    @Test\n    void assertGetServerNode() {\n        assertThat(serverNode.getServerNode(\"127.0.0.1\"), is(\"servers/127.0.0.1\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/server/ServerServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.server;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ServerServiceTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    private ServerService serverService;\n    \n    @BeforeEach\n    void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\", null, \"127.0.0.1\"));\n        serverService = new ServerService(null, \"test_job\");\n        ServerNode serverNode = new ServerNode(\"test_job\");\n        ReflectionUtils.setFieldValue(serverService, \"serverNode\", serverNode);\n        ReflectionUtils.setFieldValue(serverService, \"jobNodeStorage\", jobNodeStorage);\n    }\n    \n    @Test\n    void assertPersistOnlineForInstanceShutdown() {\n        JobRegistry.getInstance().shutdown(\"test_job\");\n        serverService.persistOnline(false);\n        verify(jobNodeStorage, times(0)).fillJobNode(\"servers/127.0.0.1\", ServerStatus.DISABLED.name());\n    }\n    \n    @Test\n    void assertPersistOnlineForDisabledServer() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        serverService.persistOnline(false);\n        verify(jobNodeStorage).fillJobNode(\"servers/127.0.0.1\", ServerStatus.DISABLED.name());\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertPersistOnlineForEnabledServer() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        serverService.persistOnline(true);\n        verify(jobNodeStorage).fillJobNode(\"servers/127.0.0.1\", ServerStatus.ENABLED.name());\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertHasAvailableServers() {\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"servers\")).thenReturn(Arrays.asList(\"127.0.0.1\", \"127.0.0.2\", \"127.0.0.3\"));\n        when(jobNodeStorage.getJobNodeData(\"servers/127.0.0.1\")).thenReturn(ServerStatus.DISABLED.name());\n        when(jobNodeStorage.getJobNodeData(\"servers/127.0.0.2\")).thenReturn(ServerStatus.ENABLED.name());\n        when(jobNodeStorage.getJobNodeData(\"servers/127.0.0.3\")).thenReturn(ServerStatus.ENABLED.name());\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"instances\")).thenReturn(Collections.singletonList(\"127.0.0.3@-@0\"));\n        assertTrue(serverService.hasAvailableServers());\n    }\n    \n    @Test\n    void assertHasNotAvailableServers() {\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"servers\")).thenReturn(Arrays.asList(\"127.0.0.1\", \"127.0.0.2\"));\n        when(jobNodeStorage.getJobNodeData(\"servers/127.0.0.1\")).thenReturn(ServerStatus.DISABLED.name());\n        when(jobNodeStorage.getJobNodeData(\"servers/127.0.0.2\")).thenReturn(ServerStatus.DISABLED.name());\n        assertFalse(serverService.hasAvailableServers());\n    }\n    \n    @Test\n    void assertIsNotAvailableServerWhenDisabled() {\n        when(jobNodeStorage.getJobNodeData(\"servers/127.0.0.1\")).thenReturn(ServerStatus.DISABLED.name());\n        assertFalse(serverService.isAvailableServer(\"127.0.0.1\"));\n    }\n    \n    @Test\n    void assertIsNotAvailableServerWithoutOnlineInstances() {\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"instances\")).thenReturn(Collections.singletonList(\"127.0.0.2@-@0\"));\n        when(jobNodeStorage.getJobNodeData(\"servers/127.0.0.1\")).thenReturn(ServerStatus.ENABLED.name());\n        assertFalse(serverService.isAvailableServer(\"127.0.0.1\"));\n    }\n    \n    @Test\n    void assertIsAvailableServer() {\n        when(jobNodeStorage.getJobNodeChildrenKeys(\"instances\")).thenReturn(Collections.singletonList(\"127.0.0.1@-@0\"));\n        when(jobNodeStorage.getJobNodeData(\"servers/127.0.0.1\")).thenReturn(ServerStatus.ENABLED.name());\n        assertTrue(serverService.isAvailableServer(\"127.0.0.1\"));\n    }\n    \n    @Test\n    void assertIsNotEnableServer() {\n        when(jobNodeStorage.getJobNodeData(\"servers/127.0.0.1\")).thenReturn(\"\", ServerStatus.DISABLED.name());\n        assertFalse(serverService.isEnableServer(\"127.0.0.1\"));\n    }\n    \n    @Test\n    void assertIsEnableServer() {\n        when(jobNodeStorage.getJobNodeData(\"servers/127.0.0.1\")).thenReturn(\"\", ServerStatus.ENABLED.name());\n        assertTrue(serverService.isEnableServer(\"127.0.0.1\"));\n    }\n    \n    @Test\n    void assertServerNodeAbsent() {\n        assertFalse(serverService.isEnableServer(\"127.0.0.1\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/setup/DefaultJobClassNameProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.setup;\n\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.job.DetailedFooJob;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.job.FooJob;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass DefaultJobClassNameProviderTest {\n    \n    @Test\n    void assertGetOrdinaryClassJobName() {\n        JobClassNameProvider jobClassNameProvider = new DefaultJobClassNameProvider();\n        String result = jobClassNameProvider.getJobClassName(new DetailedFooJob());\n        assertThat(result, is(\"org.apache.shardingsphere.elasticjob.kernel.fixture.job.DetailedFooJob\"));\n    }\n    \n    @Test\n    void assertGetLambdaJobName() {\n        JobClassNameProvider jobClassNameProvider = new DefaultJobClassNameProvider();\n        FooJob lambdaFooJob = shardingContext -> {\n        };\n        String result = jobClassNameProvider.getJobClassName(lambdaFooJob);\n        assertThat(result, is(\"org.apache.shardingsphere.elasticjob.kernel.internal.setup.DefaultJobClassNameProviderTest$$Lambda\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/setup/JobClassNameProviderFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.setup;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.instanceOf;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass JobClassNameProviderFactoryTest {\n    \n    @Test\n    void assertGetDefaultStrategy() {\n        assertThat(JobClassNameProviderFactory.getProvider(), instanceOf(DefaultJobClassNameProvider.class));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/setup/SetUpFacadeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.setup;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.ListenerManager;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.reconcile.ReconcileService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Collections;\n\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass SetUpFacadeTest {\n    \n    @Mock\n    private LeaderService leaderService;\n    \n    @Mock\n    private ServerService serverService;\n    \n    @Mock\n    private InstanceService instanceService;\n    \n    @Mock\n    private ReconcileService reconcileService;\n    \n    @Mock\n    private ListenerManager listenerManager;\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    private SetUpFacade setUpFacade;\n    \n    @BeforeEach\n    void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        setUpFacade = new SetUpFacade(regCenter, \"test_job\", Collections.emptyList());\n        ReflectionUtils.setFieldValue(setUpFacade, \"leaderService\", leaderService);\n        ReflectionUtils.setFieldValue(setUpFacade, \"serverService\", serverService);\n        ReflectionUtils.setFieldValue(setUpFacade, \"instanceService\", instanceService);\n        ReflectionUtils.setFieldValue(setUpFacade, \"reconcileService\", reconcileService);\n        ReflectionUtils.setFieldValue(setUpFacade, \"listenerManager\", listenerManager);\n    }\n    \n    @Test\n    void assertRegisterStartUpInfo() {\n        setUpFacade.registerStartUpInfo(true);\n        verify(listenerManager).startAllListeners();\n        verify(leaderService).electLeader();\n        verify(serverService).persistOnline(true);\n    }\n    \n    @Test\n    void assertTearDown() {\n        when(reconcileService.isRunning()).thenReturn(true);\n        setUpFacade.tearDown();\n        verify(reconcileService).stopAsync();\n        verify(regCenter).removeDataListeners(\"/test_job\");\n        verify(regCenter).removeConnStateListener(\"/test_job\");\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ExecutionContextServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport com.google.common.collect.Lists;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ExecutionContextServiceTest {\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private ConfigurationService configService;\n    \n    private final ExecutionContextService executionContextService = new ExecutionContextService(null, \"test_job\");\n    \n    @BeforeEach\n    void setUp() {\n        ReflectionUtils.setFieldValue(executionContextService, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(executionContextService, \"configService\", configService);\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n    }\n    \n    @Test\n    void assertGetShardingContextWhenNotAssignShardingItem() {\n        when(configService.load(false)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3)\n                .cron(\"0/1 * * * * ?\").setProperty(\"streaming.process\", Boolean.TRUE.toString()).monitorExecution(false).build());\n        ShardingContexts shardingContexts = executionContextService.getJobShardingContext(Collections.emptyList());\n        assertTrue(shardingContexts.getTaskId().startsWith(\"test_job@-@@-@READY@-@\"));\n        assertThat(shardingContexts.getShardingTotalCount(), is(3));\n    }\n    \n    @Test\n    void assertGetShardingContextWhenAssignShardingItems() {\n        when(configService.load(false)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3)\n                .cron(\"0/1 * * * * ?\").shardingItemParameters(\"0=A,1=B,2=C\").setProperty(\"streaming.process\", Boolean.TRUE.toString()).monitorExecution(false).build());\n        Map<Integer, String> map = new HashMap<>(3);\n        map.put(0, \"A\");\n        map.put(1, \"B\");\n        ShardingContexts expected = new ShardingContexts(\"fake_task_id\", \"test_job\", 3, \"\", map);\n        assertShardingContext(executionContextService.getJobShardingContext(Arrays.asList(0, 1)), expected);\n    }\n    \n    @Test\n    void assertGetShardingContextWhenHasRunningItems() {\n        when(configService.load(false)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3)\n                .cron(\"0/1 * * * * ?\").shardingItemParameters(\"0=A,1=B,2=C\").setProperty(\"streaming.process\", Boolean.TRUE.toString()).monitorExecution(true).build());\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/running\")).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/running\")).thenReturn(true);\n        Map<Integer, String> map = new HashMap<>(1, 1);\n        map.put(0, \"A\");\n        ShardingContexts expected = new ShardingContexts(\"fake_task_id\", \"test_job\", 3, \"\", map);\n        assertShardingContext(executionContextService.getJobShardingContext(Lists.newArrayList(0, 1)), expected);\n    }\n    \n    private void assertShardingContext(final ShardingContexts actual, final ShardingContexts expected) {\n        assertThat(actual.getJobName(), is(expected.getJobName()));\n        assertThat(actual.getShardingTotalCount(), is(expected.getShardingTotalCount()));\n        assertThat(actual.getJobParameter(), is(expected.getJobParameter()));\n        assertThat(actual.getShardingItemParameters().size(), is(expected.getShardingItemParameters().size()));\n        for (int i = 0; i < expected.getShardingItemParameters().size(); i++) {\n            assertThat(actual.getShardingItemParameters().get(i), is(expected.getShardingItemParameters().get(i)));\n        }\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ExecutionServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.lenient;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ExecutionServiceTest {\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private ConfigurationService configService;\n    \n    private final ExecutionService executionService = new ExecutionService(null, \"test_job\");\n    \n    @BeforeEach\n    void setUp() {\n        ReflectionUtils.setFieldValue(executionService, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(executionService, \"configService\", configService);\n    }\n    \n    @AfterEach\n    void tearDown() {\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertRegisterJobBeginWithoutMonitorExecution() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(false).build());\n        executionService.registerJobBegin(getShardingContext());\n        verify(jobNodeStorage, times(0)).fillEphemeralJobNode(any(), any());\n        assertTrue(JobRegistry.getInstance().isJobRunning(\"test_job\"));\n    }\n    \n    @Test\n    void assertRegisterJobBeginWithMonitorExecution() {\n        String jobInstanceId = \"127.0.0.1@-@1\";\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(jobInstanceId));\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(true).build());\n        executionService.registerJobBegin(getShardingContext());\n        verify(jobNodeStorage).fillEphemeralJobNode(\"sharding/0/running\", jobInstanceId);\n        verify(jobNodeStorage).fillEphemeralJobNode(\"sharding/1/running\", jobInstanceId);\n        verify(jobNodeStorage).fillEphemeralJobNode(\"sharding/2/running\", jobInstanceId);\n        assertTrue(JobRegistry.getInstance().isJobRunning(\"test_job\"));\n    }\n    \n    @Test\n    void assertRegisterJobBeginWithFailoverEnabled() {\n        String jobInstanceId = \"127.0.0.1@-@1\";\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(jobInstanceId));\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").failover(true).build());\n        executionService.registerJobBegin(getShardingContext());\n        verify(jobNodeStorage).fillJobNode(\"sharding/0/running\", jobInstanceId);\n        verify(jobNodeStorage).fillJobNode(\"sharding/1/running\", jobInstanceId);\n        verify(jobNodeStorage).fillJobNode(\"sharding/2/running\", jobInstanceId);\n        assertTrue(JobRegistry.getInstance().isJobRunning(\"test_job\"));\n    }\n    \n    @Test\n    void assertRegisterJobCompletedWithoutMonitorExecution() {\n        JobRegistry.getInstance().setJobRunning(\"test_job\", true);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(false).build());\n        executionService.registerJobCompleted(new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", Collections.emptyMap()));\n        verify(jobNodeStorage, times(0)).removeJobNodeIfExisted(any());\n        verify(jobNodeStorage, times(0)).createJobNodeIfNeeded(any());\n        assertFalse(JobRegistry.getInstance().isJobRunning(\"test_job\"));\n    }\n    \n    @Test\n    void assertRegisterJobCompletedWithMonitorExecution() {\n        JobRegistry.getInstance().setJobRunning(\"test_job\", true);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(true).build());\n        executionService.registerJobCompleted(getShardingContext());\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/0/running\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/1/running\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/2/running\");\n        assertFalse(JobRegistry.getInstance().isJobRunning(\"test_job\"));\n    }\n    \n    @Test\n    void assertClearAllRunningInfo() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(false).build());\n        executionService.clearAllRunningInfo();\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/0/running\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/1/running\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/2/running\");\n    }\n    \n    @Test\n    void assertClearRunningInfo() {\n        executionService.clearRunningInfo(Arrays.asList(0, 1));\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/0/running\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/1/running\");\n    }\n    \n    @Test\n    void assertNotHaveRunningItemsWithoutMonitorExecution() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(false).build());\n        assertFalse(executionService.hasRunningItems(Arrays.asList(0, 1, 2)));\n    }\n    \n    @Test\n    void assertHasRunningItemsWithMonitorExecution() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(true).build());\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/running\")).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/running\")).thenReturn(true);\n        assertTrue(executionService.hasRunningItems(Arrays.asList(0, 1, 2)));\n    }\n    \n    @Test\n    void assertNotHaveRunningItems() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(true).build());\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/running\")).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/running\")).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/2/running\")).thenReturn(false);\n        assertFalse(executionService.hasRunningItems(Arrays.asList(0, 1, 2)));\n    }\n    \n    @Test\n    void assertHasRunningItemsForAll() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/running\")).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/running\")).thenReturn(true);\n        assertTrue(executionService.hasRunningItems());\n    }\n    \n    @Test\n    void assertNotHaveRunningItemsForAll() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/running\")).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/running\")).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/2/running\")).thenReturn(false);\n        assertFalse(executionService.hasRunningItems());\n    }\n    \n    @Test\n    void assertGetAllRunningItems() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).build());\n        String jobInstanceId = \"127.0.0.1@-@1\";\n        when(jobNodeStorage.getJobNodeData(\"sharding/0/running\")).thenReturn(jobInstanceId);\n        lenient().when(jobNodeStorage.getJobNodeData(\"sharding/2/running\")).thenReturn(jobInstanceId);\n        Map<Integer, JobInstance> actual = executionService.getAllRunningItems();\n        assertThat(actual.size(), is(2));\n        assertThat(actual.get(0), is(new JobInstance(jobInstanceId)));\n        assertThat(actual.get(2), is(new JobInstance(jobInstanceId)));\n    }\n    \n    @Test\n    void assertMisfireIfNotRunning() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(true).build());\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/running\")).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/running\")).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/2/running\")).thenReturn(false);\n        assertFalse(executionService.misfireIfHasRunningItems(Arrays.asList(0, 1, 2)));\n    }\n    \n    @Test\n    void assertMisfireIfRunning() {\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(true).build());\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/running\")).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/running\")).thenReturn(true);\n        assertTrue(executionService.misfireIfHasRunningItems(Arrays.asList(0, 1, 2)));\n    }\n    \n    @Test\n    void assertSetMisfire() {\n        executionService.setMisfire(Arrays.asList(0, 1, 2));\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"sharding/0/misfire\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"sharding/1/misfire\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"sharding/2/misfire\");\n    }\n    \n    @Test\n    void assertGetMisfiredJobItems() {\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/misfire\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/misfire\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/2/misfire\")).thenReturn(false);\n        assertThat(executionService.getMisfiredJobItems(Arrays.asList(0, 1, 2)), is(Arrays.asList(0, 1)));\n    }\n    \n    @Test\n    void assertClearMisfire() {\n        executionService.clearMisfire(Arrays.asList(0, 1, 2));\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/0/misfire\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/1/misfire\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/2/misfire\");\n    }\n    \n    @Test\n    void assertGetDisabledItems() {\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/disabled\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/1/disabled\")).thenReturn(true);\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/2/disabled\")).thenReturn(false);\n        assertThat(executionService.getDisabledItems(Arrays.asList(0, 1, 2)), is(Arrays.asList(0, 1)));\n    }\n    \n    private ShardingContexts getShardingContext() {\n        Map<Integer, String> map = new HashMap<>(3, 1);\n        map.put(0, \"\");\n        map.put(1, \"\");\n        map.put(2, \"\");\n        return new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", map);\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/JobInstanceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.env.IpUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass JobInstanceTest {\n    \n    @Test\n    void assertGetJobInstanceId() {\n        assertThat(new JobInstance(\"127.0.0.1@-@0\").getJobInstanceId(), is(\"127.0.0.1@-@0\"));\n    }\n    \n    @Test\n    void assertGetIp() {\n        assertThat(new JobInstance().getServerIp(), is(IpUtils.getIp()));\n    }\n    \n    @Test\n    void assertYamlConvert() {\n        JobInstance actual = YamlEngine.unmarshal(YamlEngine.marshal(new JobInstance(\"id\", \"labels\")), JobInstance.class);\n        assertThat(actual.getJobInstanceId(), is(\"id\"));\n        assertThat(actual.getServerIp(), is(IpUtils.getIp()));\n        assertThat(actual.getLabels(), is(\"labels\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/MonitorExecutionListenerManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.YamlConstants;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass MonitorExecutionListenerManagerTest {\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private ExecutionService executionService;\n    \n    private final MonitorExecutionListenerManager monitorExecutionListenerManager = new MonitorExecutionListenerManager(null, \"test_job\");\n    \n    @BeforeEach\n    void setUp() {\n        ReflectionUtils.setSuperclassFieldValue(monitorExecutionListenerManager, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(monitorExecutionListenerManager, \"executionService\", executionService);\n    }\n    \n    @Test\n    void assertMonitorExecutionSettingsChangedJobListenerWhenIsNotFailoverPath() {\n        monitorExecutionListenerManager.new MonitorExecutionSettingsChangedJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.ADDED, \"/test_job/other\", YamlConstants.getJobYaml()));\n        verify(executionService, times(0)).clearAllRunningInfo();\n    }\n    \n    @Test\n    void assertMonitorExecutionSettingsChangedJobListenerWhenIsFailoverPathButNotUpdate() {\n        monitorExecutionListenerManager.new MonitorExecutionSettingsChangedJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/config\", \"\"));\n        verify(executionService, times(0)).clearAllRunningInfo();\n    }\n    \n    @Test\n    void assertMonitorExecutionSettingsChangedJobListenerWhenIsFailoverPathAndUpdateButEnableFailover() {\n        monitorExecutionListenerManager.new MonitorExecutionSettingsChangedJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/config\", YamlConstants.getJobYaml()));\n        verify(executionService, times(0)).clearAllRunningInfo();\n    }\n    \n    @Test\n    void assertMonitorExecutionSettingsChangedJobListenerWhenIsFailoverPathAndUpdateButDisableFailover() {\n        DataChangedEvent event = new DataChangedEvent(Type.UPDATED, \"/test_job/config\", YamlConstants.getJobYamlWithMonitorExecution(false));\n        monitorExecutionListenerManager.new MonitorExecutionSettingsChangedJobListener().onChange(event);\n        verify(executionService).clearAllRunningInfo();\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ShardingItemParametersTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobConfigurationException;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass ShardingItemParametersTest {\n    \n    @Test\n    void assertNewWhenPairFormatInvalid() {\n        assertThrows(JobConfigurationException.class, () -> new ShardingItemParameters(\"xxx-xxx\"));\n    }\n    \n    @Test\n    void assertNewWhenItemIsNotNumber() {\n        assertThrows(JobConfigurationException.class, () -> new ShardingItemParameters(\"xxx=xxx\"));\n    }\n    \n    @Test\n    void assertGetMapWhenIsEmpty() {\n        assertThat(new ShardingItemParameters(\"\").getMap(), is(Collections.EMPTY_MAP));\n    }\n    \n    @Test\n    void assertGetMap() {\n        Map<Integer, String> expected = new HashMap<>(3);\n        expected.put(0, \"A\");\n        expected.put(1, \"B\");\n        expected.put(2, \"C\");\n        assertThat(new ShardingItemParameters(\"0=A,1=B,2=C\").getMap(), is(expected));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ShardingListenerManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport com.google.common.collect.Lists;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.fixture.YamlConstants;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ShardingListenerManagerTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private ShardingService shardingService;\n    \n    @Mock\n    private ConfigurationService configService;\n    \n    private ShardingListenerManager shardingListenerManager;\n    \n    @BeforeEach\n    void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        shardingListenerManager = new ShardingListenerManager(null, \"test_job\");\n        ReflectionUtils.setSuperclassFieldValue(shardingListenerManager, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(shardingListenerManager, \"shardingService\", shardingService);\n        ReflectionUtils.setFieldValue(shardingListenerManager, \"configService\", configService);\n    }\n    \n    @Test\n    void assertStart() {\n        shardingListenerManager.start();\n        verify(jobNodeStorage, times(2)).addDataListener(any(DataChangedEventListener.class));\n    }\n    \n    @Test\n    void assertShardingTotalCountChangedJobListenerWhenIsNotConfigPath() {\n        shardingListenerManager.new ShardingTotalCountChangedJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/config/other\", \"\"));\n        verify(shardingService, times(0)).setReshardingFlag();\n    }\n    \n    @Test\n    void assertShardingTotalCountChangedJobListenerWhenIsConfigPathButCurrentShardingTotalCountIsZero() {\n        shardingListenerManager.new ShardingTotalCountChangedJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/config\", YamlConstants.getJobYaml()));\n        verify(shardingService, times(0)).setReshardingFlag();\n    }\n    \n    @Test\n    void assertShardingTotalCountChangedJobListenerWhenIsConfigPathAndCurrentShardingTotalCountIsEqualToNewShardingTotalCount() {\n        JobRegistry.getInstance().setCurrentShardingTotalCount(\"test_job\", 3);\n        shardingListenerManager.new ShardingTotalCountChangedJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/config\", YamlConstants.getJobYaml()));\n        verify(shardingService, times(0)).setReshardingFlag();\n        JobRegistry.getInstance().setCurrentShardingTotalCount(\"test_job\", 0);\n    }\n    \n    @Test\n    void assertShardingTotalCountChangedJobListenerWhenIsConfigPathAndCurrentShardingTotalCountIsNotEqualToNewShardingTotalCount() {\n        JobRegistry.getInstance().setCurrentShardingTotalCount(\"test_job\", 5);\n        shardingListenerManager.new ShardingTotalCountChangedJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/config\", YamlConstants.getJobYaml()));\n        verify(shardingService).setReshardingFlag();\n        JobRegistry.getInstance().setCurrentShardingTotalCount(\"test_job\", 0);\n    }\n    \n    @Test\n    void assertListenServersChangedJobListenerWhenIsNotServerStatusPath() {\n        shardingListenerManager.new ListenServersChangedJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/servers/127.0.0.1/other\", \"\"));\n        verify(shardingService, times(0)).setReshardingFlag();\n    }\n    \n    @Test\n    void assertListenServersChangedJobListenerWhenIsServerStatusPathButUpdate() {\n        shardingListenerManager.new ListenServersChangedJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/servers/127.0.0.1/status\", \"\"));\n        verify(shardingService, times(0)).setReshardingFlag();\n    }\n    \n    @Test\n    void assertListenServersChangedJobListenerWhenIsInstanceChangeButJobInstanceIsShutdown() {\n        shardingListenerManager.new ListenServersChangedJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/instances/xxx\", \"\"));\n        verify(shardingService, times(0)).setReshardingFlag();\n    }\n    \n    @Test\n    void assertListenServersChangedJobListenerWhenIsInstanceChange() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).build());\n        shardingListenerManager.new ListenServersChangedJobListener().onChange(new DataChangedEvent(Type.ADDED, \"/test_job/instances/xxx\", \"\"));\n        verify(shardingService).setReshardingFlag();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertListenServersChangedJobListenerWhenIsServerChange() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).build());\n        shardingListenerManager.new ListenServersChangedJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/servers/127.0.0.1\", \"\"));\n        verify(shardingService).setReshardingFlag();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertListenServersChangedJobListenerWhenIsStaticSharding() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 1).staticSharding(true).build());\n        when(regCenter.getChildrenKeys(\"/test_job/sharding\")).thenReturn(Lists.newArrayList(\"0\"));\n        shardingListenerManager.new ListenServersChangedJobListener().onChange(new DataChangedEvent(Type.UPDATED, \"/test_job/servers/127.0.0.1\", \"\"));\n        verify(shardingService, times(0)).setReshardingFlag();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ShardingNodeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass ShardingNodeTest {\n    \n    private final ShardingNode shardingNode = new ShardingNode(\"test_job\");\n    \n    @Test\n    void assertGetRunningNode() {\n        assertThat(ShardingNode.getRunningNode(0), is(\"sharding/0/running\"));\n    }\n    \n    @Test\n    void assertGetMisfireNode() {\n        assertThat(ShardingNode.getMisfireNode(0), is(\"sharding/0/misfire\"));\n    }\n    \n    @Test\n    void assertGetItemWhenNotRunningItemPath() {\n        assertNull(shardingNode.getItemByRunningItemPath(\"/test_job/sharding/0/completed\"));\n    }\n    \n    @Test\n    void assertGetItemByRunningItemPath() {\n        assertThat(shardingNode.getItemByRunningItemPath(\"/test_job/sharding/0/running\"), is(0));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/ShardingServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceNode;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.any;\nimport static org.mockito.Mockito.lenient;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ShardingServiceTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private LeaderService leaderService;\n    \n    @Mock\n    private ConfigurationService configService;\n    \n    @Mock\n    private ExecutionService executionService;\n    \n    @Mock\n    private ServerService serverService;\n    \n    @Mock\n    private InstanceService instanceService;\n    \n    private final ShardingService shardingService = new ShardingService(null, \"test_job\");\n    \n    @BeforeEach\n    void setUp() {\n        ReflectionUtils.setFieldValue(shardingService, \"jobNodeStorage\", jobNodeStorage);\n        ReflectionUtils.setFieldValue(shardingService, \"leaderService\", leaderService);\n        ReflectionUtils.setFieldValue(shardingService, \"configService\", configService);\n        ReflectionUtils.setFieldValue(shardingService, \"executionService\", executionService);\n        ReflectionUtils.setFieldValue(shardingService, \"instanceService\", instanceService);\n        ReflectionUtils.setFieldValue(shardingService, \"serverService\", serverService);\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\", null, \"127.0.0.1\"));\n    }\n    \n    @Test\n    void assertSetReshardingFlagOnLeader() {\n        when(leaderService.isLeaderUntilBlock()).thenReturn(true);\n        shardingService.setReshardingFlag();\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"leader/sharding/necessary\");\n    }\n    \n    @Test\n    void assertSetReshardingFlagOnNonLeader() {\n        when(leaderService.isLeaderUntilBlock()).thenReturn(false);\n        shardingService.setReshardingFlag();\n        verify(jobNodeStorage, times(0)).createJobNodeIfNeeded(\"leader/sharding/necessary\");\n    }\n    \n    @Test\n    void assertIsNeedSharding() {\n        when(jobNodeStorage.isJobNodeExisted(\"leader/sharding/necessary\")).thenReturn(true);\n        assertTrue(shardingService.isNeedSharding());\n    }\n    \n    @Test\n    void assertShardingWhenUnnecessary() {\n        shardingService.shardingIfNecessary();\n        verify(jobNodeStorage, times(0)).fillEphemeralJobNode(ShardingNode.PROCESSING, \"\");\n    }\n    \n    @Test\n    void assertShardingWithoutAvailableJobInstances() {\n        when(jobNodeStorage.isJobNodeExisted(\"leader/sharding/necessary\")).thenReturn(true);\n        shardingService.shardingIfNecessary();\n        verify(jobNodeStorage, times(0)).fillEphemeralJobNode(ShardingNode.PROCESSING, \"\");\n    }\n    \n    @Test\n    void assertShardingWhenIsNotLeader() {\n        when(jobNodeStorage.isJobNodeExisted(\"leader/sharding/necessary\")).thenReturn(true, false);\n        when(instanceService.getAvailableJobInstances()).thenReturn(Collections.singletonList(new JobInstance(\"127.0.0.1@-@0\")));\n        when(leaderService.isLeaderUntilBlock()).thenReturn(false);\n        when(jobNodeStorage.isJobNodeExisted(\"leader/sharding/processing\")).thenReturn(true, false);\n        shardingService.shardingIfNecessary();\n        verify(jobNodeStorage, times(0)).fillEphemeralJobNode(ShardingNode.PROCESSING, \"\");\n    }\n    \n    @Test\n    void assertShardingNecessaryWhenMonitorExecutionEnabledAndIncreaseShardingTotalCount() {\n        when(instanceService.getAvailableJobInstances()).thenReturn(Collections.singletonList(new JobInstance(\"127.0.0.1@-@0\")));\n        when(jobNodeStorage.isJobNodeExisted(\"leader/sharding/necessary\")).thenReturn(true);\n        when(leaderService.isLeaderUntilBlock()).thenReturn(true);\n        when(configService.load(false)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(true).build());\n        when(executionService.hasRunningItems()).thenReturn(true, false);\n        when(jobNodeStorage.getJobNodeChildrenKeys(ShardingNode.ROOT)).thenReturn(Arrays.asList(\"0\", \"1\"));\n        shardingService.shardingIfNecessary();\n        verify(executionService, times(2)).hasRunningItems();\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/0/instance\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"sharding/0\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/1/instance\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"sharding/1\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/2/instance\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"sharding/2\");\n        verify(jobNodeStorage).fillEphemeralJobNode(\"leader/sharding/processing\", \"\");\n        verify(jobNodeStorage).executeInTransaction(any(List.class));\n    }\n    \n    @Test\n    void assertShardingNecessaryWhenMonitorExecutionDisabledAndDecreaseShardingTotalCount() {\n        when(instanceService.getAvailableJobInstances()).thenReturn(Collections.singletonList(new JobInstance(\"127.0.0.1@-@0\")));\n        when(jobNodeStorage.isJobNodeExisted(\"leader/sharding/necessary\")).thenReturn(true);\n        when(leaderService.isLeaderUntilBlock()).thenReturn(true);\n        when(configService.load(false)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").monitorExecution(false).build());\n        when(jobNodeStorage.getJobNodeChildrenKeys(ShardingNode.ROOT)).thenReturn(Arrays.asList(\"0\", \"1\", \"2\", \"3\"));\n        shardingService.shardingIfNecessary();\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/0/instance\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"sharding/0\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/1/instance\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"sharding/1\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/2/instance\");\n        verify(jobNodeStorage).createJobNodeIfNeeded(\"sharding/2\");\n        verify(jobNodeStorage, times(0)).removeJobNodeIfExisted(\"execution/2\");\n        verify(jobNodeStorage).removeJobNodeIfExisted(\"sharding/3\");\n        verify(jobNodeStorage).fillEphemeralJobNode(\"leader/sharding/processing\", \"\");\n        verify(jobNodeStorage).executeInTransaction(any(List.class));\n    }\n    \n    @Test\n    void assertGetShardingItemsWithNotAvailableServer() {\n        when(jobNodeStorage.getJobNodeData(\"instances/127.0.0.1@-@0\")).thenReturn(\"jobInstanceId: 127.0.0.1@-@0\\nserverIp: 127.0.0.1\\n\");\n        assertThat(shardingService.getShardingItems(\"127.0.0.1@-@0\"), is(Collections.<Integer>emptyList()));\n    }\n    \n    @Test\n    void assertGetShardingItemsWithAvailableServer() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(serverService.isAvailableServer(\"127.0.0.1\")).thenReturn(true);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.getJobNodeData(\"sharding/0/instance\")).thenReturn(\"127.0.0.1@-@0\");\n        when(jobNodeStorage.getJobNodeData(\"sharding/1/instance\")).thenReturn(\"127.0.0.1@-@1\");\n        when(jobNodeStorage.getJobNodeData(\"sharding/2/instance\")).thenReturn(\"127.0.0.1@-@0\");\n        when(jobNodeStorage.getJobNodeData(\"instances/127.0.0.1@-@0\")).thenReturn(\"jobInstanceId: 127.0.0.1@-@0\\nserverIp: 127.0.0.1\\n\");\n        assertThat(shardingService.getShardingItems(\"127.0.0.1@-@0\"), is(Arrays.asList(0, 2)));\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertGetLocalShardingItemsWithInstanceShutdown() {\n        assertThat(shardingService.getLocalShardingItems(), is(Collections.<Integer>emptyList()));\n    }\n    \n    @Test\n    void assertGetLocalShardingItemsWithDisabledServer() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        assertThat(shardingService.getLocalShardingItems(), is(Collections.<Integer>emptyList()));\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertGetLocalShardingItemsWithEnabledServer() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(serverService.isAvailableServer(\"127.0.0.1\")).thenReturn(true);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.getJobNodeData(\"sharding/0/instance\")).thenReturn(\"127.0.0.1@-@0\");\n        when(jobNodeStorage.getJobNodeData(\"sharding/1/instance\")).thenReturn(\"127.0.0.1@-@1\");\n        when(jobNodeStorage.getJobNodeData(\"sharding/2/instance\")).thenReturn(\"127.0.0.1@-@0\");\n        when(jobNodeStorage.getJobNodeData(\"instances/127.0.0.1@-@0\")).thenReturn(\"jobInstanceId: 127.0.0.1@-@0\\nserverIp: 127.0.0.1\\n\");\n        assertThat(shardingService.getLocalShardingItems(), is(Arrays.asList(0, 2)));\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertHasShardingInfoInOfflineServers() {\n        when(jobNodeStorage.getJobNodeChildrenKeys(InstanceNode.ROOT)).thenReturn(Arrays.asList(\"host0@-@0\", \"host0@-@1\"));\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.getJobNodeData(ShardingNode.getInstanceNode(0))).thenReturn(\"host0@-@0\");\n        when(jobNodeStorage.getJobNodeData(ShardingNode.getInstanceNode(1))).thenReturn(\"host0@-@1\");\n        when(jobNodeStorage.getJobNodeData(ShardingNode.getInstanceNode(2))).thenReturn(\"host0@-@2\");\n        assertTrue(shardingService.hasShardingInfoInOfflineServers());\n    }\n    \n    @Test\n    void assertHasNotShardingInfoInOfflineServers() {\n        when(jobNodeStorage.getJobNodeChildrenKeys(InstanceNode.ROOT)).thenReturn(Arrays.asList(\"host0@-@0\", \"host0@-@1\"));\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.getJobNodeData(ShardingNode.getInstanceNode(0))).thenReturn(\"host0@-@0\");\n        when(jobNodeStorage.getJobNodeData(ShardingNode.getInstanceNode(1))).thenReturn(\"host0@-@1\");\n        when(jobNodeStorage.getJobNodeData(ShardingNode.getInstanceNode(2))).thenReturn(\"host0@-@0\");\n        assertFalse(shardingService.hasShardingInfoInOfflineServers());\n    }\n    \n    @Test\n    void assertGetCrashedShardingItemsWithNotEnableServer() {\n        assertThat(shardingService.getCrashedShardingItems(\"127.0.0.1@-@0\"), is(Collections.<Integer>emptyList()));\n    }\n    \n    @Test\n    void assertGetCrashedShardingItemsWithEnabledServer() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        when(serverService.isEnableServer(\"127.0.0.1\")).thenReturn(true);\n        when(configService.load(true)).thenReturn(JobConfiguration.newBuilder(\"test_job\", 3).cron(\"0/1 * * * * ?\").build());\n        when(jobNodeStorage.getJobNodeData(\"sharding/0/instance\")).thenReturn(\"127.0.0.1@-@0\");\n        when(jobNodeStorage.isJobNodeExisted(\"sharding/0/running\")).thenReturn(true);\n        when(jobNodeStorage.getJobNodeData(\"sharding/2/instance\")).thenReturn(\"127.0.0.1@-@0\");\n        lenient().when(jobNodeStorage.isJobNodeExisted(\"sharding/2/running\")).thenReturn(true);\n        assertThat(shardingService.getCrashedShardingItems(\"127.0.0.1@-@0\"), is(Arrays.asList(0, 2)));\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/strategy/type/AverageAllocationJobShardingStrategyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.JobShardingStrategy;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass AverageAllocationJobShardingStrategyTest {\n    \n    private final JobShardingStrategy jobShardingStrategy = new AverageAllocationJobShardingStrategy();\n    \n    @Test\n    void shardingForZeroServer() {\n        assertThat(jobShardingStrategy.sharding(Collections.emptyList(), \"test_job\", 3), is(Collections.<JobInstance, List<Integer>>emptyMap()));\n    }\n    \n    @Test\n    void shardingForOneServer() {\n        Map<JobInstance, List<Integer>> expected = new LinkedHashMap<>(1, 1);\n        expected.put(new JobInstance(\"host0@-@0\"), Arrays.asList(0, 1, 2));\n        assertThat(jobShardingStrategy.sharding(Collections.singletonList(new JobInstance(\"host0@-@0\")), \"test_job\", 3), is(expected));\n    }\n    \n    @Test\n    void shardingForServersMoreThanShardingCount() {\n        Map<JobInstance, List<Integer>> expected = new LinkedHashMap<>(3, 1);\n        expected.put(new JobInstance(\"host0@-@0\"), Collections.singletonList(0));\n        expected.put(new JobInstance(\"host1@-@0\"), Collections.singletonList(1));\n        expected.put(new JobInstance(\"host2@-@0\"), Collections.emptyList());\n        assertThat(jobShardingStrategy.sharding(Arrays.asList(new JobInstance(\"host0@-@0\"), new JobInstance(\"host1@-@0\"), new JobInstance(\"host2@-@0\")), \"test_job\", 2), is(expected));\n    }\n    \n    @Test\n    void shardingForServersLessThanShardingCountAliquot() {\n        Map<JobInstance, List<Integer>> expected = new LinkedHashMap<>(3, 1);\n        expected.put(new JobInstance(\"host0@-@0\"), Arrays.asList(0, 1, 2));\n        expected.put(new JobInstance(\"host1@-@0\"), Arrays.asList(3, 4, 5));\n        expected.put(new JobInstance(\"host2@-@0\"), Arrays.asList(6, 7, 8));\n        assertThat(jobShardingStrategy.sharding(Arrays.asList(new JobInstance(\"host0@-@0\"), new JobInstance(\"host1@-@0\"), new JobInstance(\"host2@-@0\")), \"test_job\", 9), is(expected));\n    }\n    \n    @Test\n    void shardingForServersLessThanShardingCountAliquantFor8ShardingCountAnd3Servers() {\n        Map<JobInstance, List<Integer>> expected = new LinkedHashMap<>(3, 1);\n        expected.put(new JobInstance(\"host0@-@0\"), Arrays.asList(0, 1, 6));\n        expected.put(new JobInstance(\"host1@-@0\"), Arrays.asList(2, 3, 7));\n        expected.put(new JobInstance(\"host2@-@0\"), Arrays.asList(4, 5));\n        assertThat(jobShardingStrategy.sharding(Arrays.asList(new JobInstance(\"host0@-@0\"), new JobInstance(\"host1@-@0\"), new JobInstance(\"host2@-@0\")), \"test_job\", 8), is(expected));\n    }\n    \n    @Test\n    void shardingForServersLessThanShardingCountAliquantFor10ShardingCountAnd3Servers() {\n        Map<JobInstance, List<Integer>> expected = new LinkedHashMap<>(3, 1);\n        expected.put(new JobInstance(\"host0@-@0\"), Arrays.asList(0, 1, 2, 9));\n        expected.put(new JobInstance(\"host1@-@0\"), Arrays.asList(3, 4, 5));\n        expected.put(new JobInstance(\"host2@-@0\"), Arrays.asList(6, 7, 8));\n        assertThat(jobShardingStrategy.sharding(Arrays.asList(new JobInstance(\"host0@-@0\"), new JobInstance(\"host1@-@0\"), new JobInstance(\"host2@-@0\")), \"test_job\", 10), is(expected));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/strategy/type/OdevitySortByNameJobShardingStrategyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass OdevitySortByNameJobShardingStrategyTest {\n    \n    private final OdevitySortByNameJobShardingStrategy odevitySortByNameJobShardingStrategy = new OdevitySortByNameJobShardingStrategy();\n    \n    @Test\n    void assertShardingByAsc() {\n        Map<JobInstance, List<Integer>> expected = new HashMap<>();\n        expected.put(new JobInstance(\"host0@-@0\"), Collections.singletonList(0));\n        expected.put(new JobInstance(\"host1@-@0\"), Collections.singletonList(1));\n        expected.put(new JobInstance(\"host2@-@0\"), Collections.emptyList());\n        assertThat(odevitySortByNameJobShardingStrategy.sharding(Arrays.asList(new JobInstance(\"host0@-@0\"), new JobInstance(\"host1@-@0\"), new JobInstance(\"host2@-@0\")), \"1\", 2), is(expected));\n    }\n    \n    @Test\n    void assertShardingByDesc() {\n        Map<JobInstance, List<Integer>> expected = new HashMap<>();\n        expected.put(new JobInstance(\"host2@-@0\"), Collections.singletonList(0));\n        expected.put(new JobInstance(\"host1@-@0\"), Collections.singletonList(1));\n        expected.put(new JobInstance(\"host0@-@0\"), Collections.emptyList());\n        assertThat(odevitySortByNameJobShardingStrategy.sharding(Arrays.asList(new JobInstance(\"host0@-@0\"), new JobInstance(\"host1@-@0\"), new JobInstance(\"host2@-@0\")), \"0\", 2), is(expected));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/strategy/type/RotateServerByNameJobShardingStrategyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass RotateServerByNameJobShardingStrategyTest {\n    \n    private final RoundRobinByNameJobShardingStrategy rotateServerByNameJobShardingStrategy = new RoundRobinByNameJobShardingStrategy();\n    \n    @Test\n    void assertSharding1() {\n        Map<JobInstance, List<Integer>> expected = new HashMap<>();\n        expected.put(new JobInstance(\"host1@-@0\"), Collections.singletonList(0));\n        expected.put(new JobInstance(\"host2@-@0\"), Collections.singletonList(1));\n        expected.put(new JobInstance(\"host0@-@0\"), Collections.emptyList());\n        assertThat(rotateServerByNameJobShardingStrategy.sharding(Arrays.asList(new JobInstance(\"host0@-@0\"), new JobInstance(\"host1@-@0\"), new JobInstance(\"host2@-@0\")), \"1\", 2), is(expected));\n    }\n    \n    @Test\n    void assertSharding2() {\n        Map<JobInstance, List<Integer>> expected = new HashMap<>();\n        expected.put(new JobInstance(\"host2@-@0\"), Collections.singletonList(0));\n        expected.put(new JobInstance(\"host0@-@0\"), Collections.singletonList(1));\n        expected.put(new JobInstance(\"host1@-@0\"), Collections.emptyList());\n        assertThat(rotateServerByNameJobShardingStrategy.sharding(Arrays.asList(new JobInstance(\"host0@-@0\"), new JobInstance(\"host1@-@0\"), new JobInstance(\"host2@-@0\")), \"2\", 2), is(expected));\n    }\n    \n    @Test\n    void assertSharding3() {\n        Map<JobInstance, List<Integer>> expected = new HashMap<>();\n        expected.put(new JobInstance(\"host0@-@0\"), Collections.singletonList(0));\n        expected.put(new JobInstance(\"host1@-@0\"), Collections.singletonList(1));\n        expected.put(new JobInstance(\"host2@-@0\"), Collections.emptyList());\n        assertThat(rotateServerByNameJobShardingStrategy.sharding(Arrays.asList(new JobInstance(\"host0@-@0\"), new JobInstance(\"host1@-@0\"), new JobInstance(\"host2@-@0\")), \"3\", 2), is(expected));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/sharding/strategy/type/SingleShardingBalanceJobShardingStrategyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.junit.jupiter.api.Test;\n\nclass SingleShardingBalanceJobShardingStrategyTest {\n    \n    private final SingleShardingBalanceJobShardingStrategy singleShardingBalanceJobShardingStrategy = new SingleShardingBalanceJobShardingStrategy();\n    \n    @Test\n    void assertSharding() {\n        Map<JobInstance, List<Integer>> sharding = singleShardingBalanceJobShardingStrategy.sharding(\n                Arrays.asList(new JobInstance(\"host0@-@0\"), new JobInstance(\"host1@-@0\"), new JobInstance(\"host2@-@0\")),\n                \"JobName\", 1);\n        int sum = sharding.values().stream().mapToInt(List::size).sum();\n        assertThat(sum, is(1));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/storage/JobNodePathTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.storage;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass JobNodePathTest {\n    \n    private final JobNodePath jobNodePath = new JobNodePath(\"test_job\");\n    \n    @Test\n    void assertGetFullPath() {\n        assertThat(jobNodePath.getFullPath(\"node\"), is(\"/test_job/node\"));\n    }\n    \n    @Test\n    void assertGetServerNodePath() {\n        assertThat(jobNodePath.getServerNodePath(), is(\"/test_job/servers\"));\n    }\n    \n    @Test\n    void assertGetServerNodePathForServerIp() {\n        assertThat(jobNodePath.getServerNodePath(\"ip0\"), is(\"/test_job/servers/ip0\"));\n    }\n    \n    @Test\n    void assertGetShardingNodePath() {\n        assertThat(jobNodePath.getShardingNodePath(), is(\"/test_job/sharding\"));\n    }\n    \n    @Test\n    void assertGetShardingNodePathWihItemAndNode() {\n        assertThat(jobNodePath.getShardingNodePath(\"0\", \"running\"), is(\"/test_job/sharding/0/running\"));\n    }\n    \n    @Test\n    void assertGetLeaderIpNodePath() {\n        assertThat(jobNodePath.getLeaderHostNodePath(), is(\"/test_job/leader/election/instance\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/storage/JobNodeStorageTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.storage;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.listener.ListenerNotifierManager;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.base.transaction.TransactionOperation;\nimport org.apache.shardingsphere.elasticjob.reg.exception.RegException;\nimport org.apache.shardingsphere.elasticjob.reg.listener.ConnectionStateChangedEventListener;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Executor;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass JobNodeStorageTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    private JobNodeStorage jobNodeStorage;\n    \n    @BeforeEach\n    void setUp() {\n        jobNodeStorage = new JobNodeStorage(regCenter, \"test_job\");\n        ReflectionUtils.setFieldValue(jobNodeStorage, \"regCenter\", regCenter);\n    }\n    \n    @Test\n    void assertIsJobNodeExisted() {\n        when(regCenter.isExisted(\"/test_job/config\")).thenReturn(true);\n        assertTrue(jobNodeStorage.isJobNodeExisted(\"config\"));\n        verify(regCenter).isExisted(\"/test_job/config\");\n    }\n    \n    @Test\n    void assertGetJobNodeData() {\n        when(regCenter.get(\"/test_job/config/cron\")).thenReturn(\"0/1 * * * * ?\");\n        assertThat(jobNodeStorage.getJobNodeData(\"config/cron\"), is(\"0/1 * * * * ?\"));\n        verify(regCenter).get(\"/test_job/config/cron\");\n    }\n    \n    @Test\n    void assertGetJobNodeDataDirectly() {\n        when(regCenter.getDirectly(\"/test_job/config/cron\")).thenReturn(\"0/1 * * * * ?\");\n        assertThat(jobNodeStorage.getJobNodeDataDirectly(\"config/cron\"), is(\"0/1 * * * * ?\"));\n        verify(regCenter).getDirectly(\"/test_job/config/cron\");\n    }\n    \n    @Test\n    void assertGetJobNodeChildrenKeys() {\n        when(regCenter.getChildrenKeys(\"/test_job/servers\")).thenReturn(Arrays.asList(\"host0\", \"host1\"));\n        assertThat(jobNodeStorage.getJobNodeChildrenKeys(\"servers\"), is(Arrays.asList(\"host0\", \"host1\")));\n        verify(regCenter).getChildrenKeys(\"/test_job/servers\");\n    }\n    \n    @Test\n    void assertCreateJobNodeIfNeeded() {\n        when(regCenter.isExisted(\"/test_job\")).thenReturn(true);\n        when(regCenter.isExisted(\"/test_job/config\")).thenReturn(false);\n        jobNodeStorage.createJobNodeIfNeeded(\"config\");\n        verify(regCenter).isExisted(\"/test_job\");\n        verify(regCenter).isExisted(\"/test_job/config\");\n        verify(regCenter).persist(\"/test_job/config\", \"\");\n    }\n    \n    @Test\n    void assertCreateJobNodeIfRootJobNodeIsNotExist() {\n        when(regCenter.isExisted(\"/test_job\")).thenReturn(false);\n        jobNodeStorage.createJobNodeIfNeeded(\"config\");\n        verify(regCenter).isExisted(\"/test_job\");\n        verify(regCenter, times(0)).isExisted(\"/test_job/config\");\n        verify(regCenter, times(0)).persist(\"/test_job/config\", \"\");\n    }\n    \n    @Test\n    void assertCreateJobNodeIfNotNeeded() {\n        when(regCenter.isExisted(\"/test_job\")).thenReturn(true);\n        when(regCenter.isExisted(\"/test_job/config\")).thenReturn(true);\n        jobNodeStorage.createJobNodeIfNeeded(\"config\");\n        verify(regCenter).isExisted(\"/test_job\");\n        verify(regCenter).isExisted(\"/test_job/config\");\n        verify(regCenter, times(0)).persist(\"/test_job/config\", \"\");\n    }\n    \n    @Test\n    void assertRemoveJobNodeIfNeeded() {\n        when(regCenter.isExisted(\"/test_job/config\")).thenReturn(true);\n        jobNodeStorage.removeJobNodeIfExisted(\"config\");\n        verify(regCenter).isExisted(\"/test_job/config\");\n        verify(regCenter).remove(\"/test_job/config\");\n    }\n    \n    @Test\n    void assertRemoveJobNodeIfNotNeeded() {\n        when(regCenter.isExisted(\"/test_job/config\")).thenReturn(false);\n        jobNodeStorage.removeJobNodeIfExisted(\"config\");\n        verify(regCenter).isExisted(\"/test_job/config\");\n        verify(regCenter, times(0)).remove(\"/test_job/config\");\n    }\n    \n    @Test\n    void assertFillJobNode() {\n        jobNodeStorage.fillJobNode(\"config/cron\", \"0/1 * * * * ?\");\n        verify(regCenter).persist(\"/test_job/config/cron\", \"0/1 * * * * ?\");\n    }\n    \n    @Test\n    void assertFillEphemeralJobNode() {\n        jobNodeStorage.fillEphemeralJobNode(\"config/cron\", \"0/1 * * * * ?\");\n        verify(regCenter).persistEphemeral(\"/test_job/config/cron\", \"0/1 * * * * ?\");\n    }\n    \n    @Test\n    void assertUpdateJobNode() {\n        jobNodeStorage.updateJobNode(\"config/cron\", \"0/1 * * * * ?\");\n        verify(regCenter).update(\"/test_job/config/cron\", \"0/1 * * * * ?\");\n    }\n    \n    @Test\n    void assertReplaceJobNode() {\n        jobNodeStorage.replaceJobNode(\"config/cron\", \"0/1 * * * * ?\");\n        verify(regCenter).persist(\"/test_job/config/cron\", \"0/1 * * * * ?\");\n    }\n    \n    @Test\n    void assertExecuteInTransactionSuccess() throws Exception {\n        jobNodeStorage.executeInTransaction(Collections.singletonList(TransactionOperation.opAdd(\"/test_transaction\", \"\")));\n        verify(regCenter).executeInTransaction(any(List.class));\n    }\n    \n    @Test\n    void assertExecuteInTransactionFailure() {\n        assertThrows(RegException.class, () -> {\n            doThrow(RuntimeException.class).when(regCenter).executeInTransaction(any(List.class));\n            jobNodeStorage.executeInTransaction(Collections.singletonList(TransactionOperation.opAdd(\"/test_transaction\", \"\")));\n        });\n    }\n    \n    @Test\n    void assertAddConnectionStateListener() {\n        ConnectionStateChangedEventListener listener = mock(ConnectionStateChangedEventListener.class);\n        jobNodeStorage.addConnectionStateListener(listener);\n        verify(regCenter).addConnectionStateChangedEventListener(\"/test_job\", listener);\n    }\n    \n    @Test\n    void assertAddDataListener() {\n        DataChangedEventListener listener = mock(DataChangedEventListener.class);\n        String jobName = \"test_job\";\n        ListenerNotifierManager.getInstance().registerJobNotifyExecutor(jobName);\n        Executor executor = ListenerNotifierManager.getInstance().getJobNotifyExecutor(jobName);\n        jobNodeStorage.addDataListener(listener);\n        verify(regCenter).watch(\"/test_job\", listener, executor);\n    }\n    \n    @Test\n    void assertGetRegistryCenterTime() {\n        when(regCenter.getRegistryCenterTime(\"/test_job/systemTime/current\")).thenReturn(0L);\n        assertThat(jobNodeStorage.getRegistryCenterTime(), is(0L));\n        verify(regCenter).getRegistryCenterTime(\"/test_job/systemTime/current\");\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/internal/trigger/TriggerListenerManagerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.internal.trigger;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduleController;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodeStorage;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass TriggerListenerManagerTest {\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @Mock\n    private JobNodeStorage jobNodeStorage;\n    \n    @Mock\n    private TriggerService triggerService;\n    \n    @Mock\n    private JobScheduleController jobScheduleController;\n    \n    private TriggerListenerManager triggerListenerManager;\n    \n    @BeforeEach\n    void setUp() {\n        JobRegistry.getInstance().addJobInstance(\"test_job\", new JobInstance(\"127.0.0.1@-@0\"));\n        triggerListenerManager = new TriggerListenerManager(null, \"test_job\");\n        ReflectionUtils.setFieldValue(triggerListenerManager, \"triggerService\", triggerService);\n        ReflectionUtils.setSuperclassFieldValue(triggerListenerManager, \"jobNodeStorage\", jobNodeStorage);\n    }\n    \n    @Test\n    void assertStart() {\n        triggerListenerManager.start();\n        verify(jobNodeStorage).addDataListener(ArgumentMatchers.any());\n    }\n    \n    @Test\n    void assertNotTriggerWhenIsNotLocalInstancePath() {\n        triggerListenerManager.new JobTriggerStatusJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.ADDED, \"/test_job/trigger/127.0.0.2@-@0\", \"\"));\n        verify(triggerService, times(0)).removeTriggerFlag();\n    }\n    \n    @Test\n    void assertNotTriggerWhenIsNotCreate() {\n        triggerListenerManager.new JobTriggerStatusJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.UPDATED, \"/test_job/trigger/127.0.0.1@-@0\", \"\"));\n        verify(triggerService, times(0)).removeTriggerFlag();\n    }\n    \n    @Test\n    void assertTriggerWhenJobScheduleControllerIsNull() {\n        triggerListenerManager.new JobTriggerStatusJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.ADDED, \"/test_job/trigger/127.0.0.1@-@0\", \"\"));\n        verify(triggerService).removeTriggerFlag();\n        verify(jobScheduleController, times(0)).triggerJob();\n    }\n    \n    @Test\n    void assertTriggerWhenJobIsRunning() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        JobRegistry.getInstance().setJobRunning(\"test_job\", true);\n        triggerListenerManager.new JobTriggerStatusJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.ADDED, \"/test_job/trigger/127.0.0.1@-@0\", \"\"));\n        verify(triggerService).removeTriggerFlag();\n        verify(jobScheduleController, times(0)).triggerJob();\n        JobRegistry.getInstance().setJobRunning(\"test_job\", false);\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n    \n    @Test\n    void assertTriggerWhenJobIsNotRunning() {\n        JobRegistry.getInstance().registerRegistryCenter(\"test_job\", regCenter);\n        JobRegistry.getInstance().registerJob(\"test_job\", jobScheduleController);\n        triggerListenerManager.new JobTriggerStatusJobListener().onChange(new DataChangedEvent(DataChangedEvent.Type.ADDED, \"/test_job/trigger/127.0.0.1@-@0\", \"\"));\n        verify(triggerService).removeTriggerFlag();\n        verify(jobScheduleController).triggerJob();\n        JobRegistry.getInstance().shutdown(\"test_job\");\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/listener/DistributeOnceElasticJobListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.listener;\n\nimport com.google.common.collect.Sets;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.time.TimeService;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.fixture.ElasticJobListenerCaller;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.fixture.TestDistributeOnceElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.guarantee.GuaranteeService;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass DistributeOnceElasticJobListenerTest {\n    \n    @Mock\n    private GuaranteeService guaranteeService;\n    \n    @Mock\n    private TimeService timeService;\n    \n    @Mock\n    private ElasticJobListenerCaller elasticJobListenerCaller;\n    \n    private ShardingContexts shardingContexts;\n    \n    private TestDistributeOnceElasticJobListener distributeOnceElasticJobListener;\n    \n    @BeforeEach\n    void setUp() {\n        distributeOnceElasticJobListener = new TestDistributeOnceElasticJobListener(elasticJobListenerCaller);\n        distributeOnceElasticJobListener.setGuaranteeService(guaranteeService);\n        ReflectionUtils.setSuperclassFieldValue(distributeOnceElasticJobListener, \"timeService\", timeService);\n        Map<Integer, String> map = new HashMap<>(2, 1);\n        map.put(0, \"\");\n        map.put(1, \"\");\n        shardingContexts = new ShardingContexts(\"fake_task_id\", \"test_job\", 10, \"\", map);\n    }\n    \n    @Test\n    void assertBeforeJobExecutedWhenIsAllStarted() {\n        when(guaranteeService.isRegisterStartSuccess(Sets.newHashSet(0, 1))).thenReturn(true);\n        when(guaranteeService.isAllStarted()).thenReturn(true);\n        distributeOnceElasticJobListener.beforeJobExecuted(shardingContexts);\n        verify(guaranteeService).registerStart(Sets.newHashSet(0, 1));\n        verify(guaranteeService).executeInLeaderForLastStarted(distributeOnceElasticJobListener, shardingContexts);\n    }\n    \n    @Test\n    void assertBeforeJobExecutedWhenIsNotAllStartedAndNotTimeout() {\n        when(guaranteeService.isRegisterStartSuccess(Sets.newHashSet(0, 1))).thenReturn(true);\n        when(guaranteeService.isAllStarted()).thenReturn(false);\n        when(timeService.getCurrentMillis()).thenReturn(0L);\n        distributeOnceElasticJobListener.beforeJobExecuted(shardingContexts);\n        verify(guaranteeService).registerStart(Sets.newHashSet(0, 1));\n        verify(guaranteeService, times(0)).clearAllStartedInfo();\n    }\n    \n    @Test\n    void assertBeforeJobExecutedWhenIsNotAllStartedAndTimeout() {\n        assertThrows(JobSystemException.class, () -> {\n            when(guaranteeService.isRegisterStartSuccess(Sets.newHashSet(0, 1))).thenReturn(true);\n            when(guaranteeService.isAllStarted()).thenReturn(false);\n            when(timeService.getCurrentMillis()).thenReturn(0L, 2L);\n            distributeOnceElasticJobListener.beforeJobExecuted(shardingContexts);\n            verify(guaranteeService).registerStart(Arrays.asList(0, 1));\n            verify(guaranteeService, times(0)).clearAllStartedInfo();\n        });\n    }\n    \n    @Test\n    void assertAfterJobExecutedWhenIsAllCompleted() {\n        when(guaranteeService.isRegisterCompleteSuccess(Sets.newHashSet(0, 1))).thenReturn(true);\n        when(guaranteeService.isAllCompleted()).thenReturn(true);\n        distributeOnceElasticJobListener.afterJobExecuted(shardingContexts);\n        verify(guaranteeService).registerComplete(Sets.newHashSet(0, 1));\n        verify(guaranteeService).executeInLeaderForLastCompleted(distributeOnceElasticJobListener, shardingContexts);\n    }\n    \n    @Test\n    void assertAfterJobExecutedWhenIsAllCompletedAndNotTimeout() {\n        when(guaranteeService.isRegisterCompleteSuccess(Sets.newHashSet(0, 1))).thenReturn(true);\n        when(guaranteeService.isAllCompleted()).thenReturn(false);\n        when(timeService.getCurrentMillis()).thenReturn(0L);\n        distributeOnceElasticJobListener.afterJobExecuted(shardingContexts);\n        verify(guaranteeService).registerComplete(Sets.newHashSet(0, 1));\n        verify(guaranteeService, times(0)).clearAllCompletedInfo();\n    }\n    \n    @Test\n    void assertAfterJobExecutedWhenIsAllCompletedAndTimeout() {\n        assertThrows(JobSystemException.class, () -> {\n            when(guaranteeService.isRegisterCompleteSuccess(Sets.newHashSet(0, 1))).thenReturn(true);\n            when(guaranteeService.isAllCompleted()).thenReturn(false);\n            when(timeService.getCurrentMillis()).thenReturn(0L, 2L);\n            distributeOnceElasticJobListener.afterJobExecuted(shardingContexts);\n            verify(guaranteeService).registerComplete(Arrays.asList(0, 1));\n            verify(guaranteeService, times(0)).clearAllCompletedInfo();\n        });\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/listener/fixture/ElasticJobListenerCaller.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.listener.fixture;\n\npublic interface ElasticJobListenerCaller {\n    \n    /**\n     * Execute before.\n     */\n    void before();\n    \n    /**\n     * Execute after.\n     */\n    void after();\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/listener/fixture/TestDistributeOnceElasticJobListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.listener.fixture;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.AbstractDistributeOnceElasticJobListener;\n\npublic final class TestDistributeOnceElasticJobListener extends AbstractDistributeOnceElasticJobListener {\n    \n    private final ElasticJobListenerCaller caller;\n    \n    public TestDistributeOnceElasticJobListener() {\n        this(null);\n    }\n    \n    public TestDistributeOnceElasticJobListener(final ElasticJobListenerCaller caller) {\n        super(1L, 1L);\n        this.caller = caller;\n    }\n    \n    @Override\n    public void doBeforeJobExecutedAtLastStarted(final ShardingContexts shardingContexts) {\n        caller.before();\n    }\n    \n    @Override\n    public void doAfterJobExecutedAtLastCompleted(final ShardingContexts shardingContexts) {\n        caller.after();\n    }\n    \n    @Override\n    public String getType() {\n        return \"DISTRIBUTE\";\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/listener/fixture/TestElasticJobListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.listener.fixture;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\n\n@RequiredArgsConstructor\npublic final class TestElasticJobListener implements ElasticJobListener {\n    \n    private final ElasticJobListenerCaller caller;\n    \n    private final String name;\n    \n    private final int order;\n    \n    private final StringBuilder orderResult;\n    \n    public TestElasticJobListener() {\n        this(null, null, 0, new StringBuilder());\n    }\n    \n    @Override\n    public void beforeJobExecuted(final ShardingContexts shardingContexts) {\n        caller.before();\n        orderResult.append(name);\n    }\n    \n    @Override\n    public void afterJobExecuted(final ShardingContexts shardingContexts) {\n        caller.after();\n        orderResult.append(name);\n    }\n    \n    @Override\n    public String getType() {\n        return \"TEST\";\n    }\n    \n    @Override\n    public int order() {\n        return order;\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/event/JobExecutionEventTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.event;\n\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass JobExecutionEventTest {\n    \n    @Test\n    void assertNewJobExecutionEvent() {\n        JobExecutionEvent actual = new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);\n        assertThat(actual.getJobName(), is(\"test_job\"));\n        assertThat(actual.getSource(), is(JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER));\n        assertThat(actual.getShardingItem(), is(0));\n        assertNotNull(actual.getHostname());\n        assertNotNull(actual.getStartTime());\n        assertNull(actual.getCompleteTime());\n        assertFalse(actual.isSuccess());\n        assertNull(actual.getFailureCause());\n    }\n    \n    @Test\n    void assertExecutionSuccess() {\n        JobExecutionEvent startEvent = new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);\n        JobExecutionEvent successEvent = startEvent.executionSuccess();\n        assertNotNull(successEvent.getCompleteTime());\n        assertTrue(successEvent.isSuccess());\n    }\n    \n    @Test\n    void assertExecutionFailure() {\n        JobExecutionEvent startEvent = new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);\n        JobExecutionEvent failureEvent = startEvent.executionFailure(\"java.lang.RuntimeException: failure\");\n        assertNotNull(failureEvent.getCompleteTime());\n        assertFalse(failureEvent.isSuccess());\n        assertThat(failureEvent.getFailureCause(), is(\"java.lang.RuntimeException: failure\"));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/event/JobTracingEventBusTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.event;\n\nimport com.google.common.eventbus.EventBus;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config.TracingStorageFixture;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.fixture.listener.TracingListenerFixture;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass JobTracingEventBusTest {\n    \n    @Mock\n    private TracingStorageFixture tracingStorage;\n    \n    @Mock\n    private EventBus eventBus;\n    \n    private JobTracingEventBus jobTracingEventBus;\n    \n    @Test\n    void assertRegisterWithoutTracingStorageConfiguration() {\n        jobTracingEventBus = new JobTracingEventBus(new TracingConfiguration<>(\"TEST\", null));\n        assertFalse((Boolean) ReflectionUtils.getFieldValue(jobTracingEventBus, \"isRegistered\"));\n    }\n    \n    @Test\n    void assertPost() {\n        jobTracingEventBus = new JobTracingEventBus(new TracingConfiguration<>(\"TEST\", tracingStorage));\n        assertTrue((Boolean) ReflectionUtils.getFieldValue(jobTracingEventBus, \"isRegistered\"));\n        jobTracingEventBus.post(new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_event_bus_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0));\n        Awaitility.await().pollDelay(100L, TimeUnit.MILLISECONDS).until(TracingListenerFixture::isExecutionEventCalled);\n        verify(tracingStorage).call();\n    }\n    \n    @Test\n    void assertPostWithoutListener() {\n        jobTracingEventBus = new JobTracingEventBus();\n        assertFalse((Boolean) ReflectionUtils.getFieldValue(jobTracingEventBus, \"isRegistered\"));\n        ReflectionUtils.setFieldValue(jobTracingEventBus, \"eventBus\", eventBus);\n        jobTracingEventBus.post(new JobExecutionEvent(\"localhost\", \"127.0.0.1\", \"fake_task_id\", \"test_event_bus_job\", JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0));\n        verify(eventBus, times(0)).post(ArgumentMatchers.<JobEvent>any());\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/fixture/config/TracingStorageConfigurationFixture.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\n\n@RequiredArgsConstructor\n@Getter\npublic final class TracingStorageConfigurationFixture implements TracingStorageConfiguration<TracingStorageFixture> {\n    \n    private final TracingStorageFixture storage;\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/fixture/config/TracingStorageFixture.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config;\n\npublic interface TracingStorageFixture {\n    \n    /**\n     * Call.\n     */\n    void call();\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/fixture/config/TracingStorageFixtureConfigurationConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config;\n\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfigurationConverter;\n\npublic final class TracingStorageFixtureConfigurationConverter implements TracingStorageConfigurationConverter<TracingStorageFixture> {\n    \n    @Override\n    public TracingStorageConfiguration<TracingStorageFixture> toConfiguration(final TracingStorageFixture storage) {\n        return new TracingStorageConfigurationFixture(storage);\n    }\n    \n    @Override\n    public Class<TracingStorageFixture> storageType() {\n        return TracingStorageFixture.class;\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/fixture/listener/TracingListenerFixture.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.fixture.listener;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config.TracingStorageFixture;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListener;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobExecutionEvent;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.event.JobStatusTraceEvent;\n\n@RequiredArgsConstructor\npublic final class TracingListenerFixture implements TracingListener {\n    \n    @Getter\n    private static volatile boolean executionEventCalled;\n    \n    private final TracingStorageFixture tracingStorage;\n    \n    @Override\n    public void listen(final JobExecutionEvent jobExecutionEvent) {\n        tracingStorage.call();\n        executionEventCalled = true;\n    }\n    \n    @Override\n    public void listen(final JobStatusTraceEvent jobStatusTraceEvent) {\n        tracingStorage.call();\n    }\n    \n    /**\n     * Reset.\n     */\n    public static void reset() {\n        executionEventCalled = false;\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/fixture/listener/TracingListenerFixtureFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.fixture.listener;\n\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config.TracingStorageFixture;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListenerFactory;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListener;\n\npublic final class TracingListenerFixtureFactory implements TracingListenerFactory<TracingStorageFixture> {\n    \n    @Override\n    public TracingListener create(final TracingStorageFixture storage) {\n        return new TracingListenerFixture(storage);\n    }\n    \n    @Override\n    public String getType() {\n        return \"TEST\";\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/storage/TracingStorageConfigurationConverterFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.storage;\n\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config.TracingStorageFixture;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass TracingStorageConfigurationConverterFactoryTest {\n    \n    @Test\n    void assertConverterExists() {\n        assertTrue(TracingStorageConverterFactory.findConverter(TracingStorageFixture.class).isPresent());\n    }\n    \n    @Test\n    void assertConverterNotFound() {\n        assertFalse(TracingStorageConverterFactory.findConverter(AClassWithoutCorrespondingConverter.class).isPresent());\n    }\n    \n    private static class AClassWithoutCorrespondingConverter {\n        \n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/yaml/YamlJobEventCallerConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.yaml;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config.TracingStorageFixture;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config.TracingStorageConfigurationFixture;\n\n/**\n * YAML JobEventCaller configuration.\n */\n@Getter\n@Setter\npublic final class YamlJobEventCallerConfiguration implements YamlTracingStorageConfiguration<TracingStorageFixture> {\n    \n    private static final long serialVersionUID = -3152825887223378472L;\n    \n    private TracingStorageFixture tracingStorageFixture;\n    \n    @Override\n    public TracingStorageConfiguration<TracingStorageFixture> toConfiguration() {\n        return new TracingStorageConfigurationFixture(tracingStorageFixture);\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/yaml/YamlJobEventCallerConfigurationConverter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.yaml;\n\nimport org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfigurationConverter;\nimport org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config.TracingStorageFixture;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config.TracingStorageConfigurationFixture;\n\n/**\n * YAML job event caller configuration converter.\n */\n@SuppressWarnings({\"unchecked\", \"rawtypes\"})\npublic final class YamlJobEventCallerConfigurationConverter\n        implements\n            YamlConfigurationConverter<TracingStorageConfiguration<TracingStorageFixture>, YamlTracingStorageConfiguration<TracingStorageFixture>> {\n    \n    @Override\n    public YamlTracingStorageConfiguration<TracingStorageFixture> convertToYamlConfiguration(final TracingStorageConfiguration<TracingStorageFixture> data) {\n        YamlJobEventCallerConfiguration result = new YamlJobEventCallerConfiguration();\n        result.setTracingStorageFixture(data.getStorage());\n        return result;\n    }\n    \n    @Override\n    public Class getType() {\n        return TracingStorageConfigurationFixture.class;\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/java/org/apache/shardingsphere/elasticjob/kernel/tracing/yaml/YamlTracingConfigurationConverterTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.kernel.tracing.yaml;\n\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config.TracingStorageFixture;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass YamlTracingConfigurationConverterTest {\n    \n    @Test\n    void assertConvertTracingConfiguration() {\n        TracingStorageFixture expectedStorage = () -> {\n        };\n        TracingConfiguration<TracingStorageFixture> tracingConfig = new TracingConfiguration<>(\"TEST\", expectedStorage);\n        YamlTracingConfigurationConverter<TracingStorageFixture> converter = new YamlTracingConfigurationConverter<>();\n        YamlTracingConfiguration<TracingStorageFixture> actual = converter.convertToYamlConfiguration(tracingConfig);\n        assertThat(actual.getType(), is(\"TEST\"));\n        assertNotNull(actual.getTracingStorageConfiguration());\n        assertTrue(actual.getTracingStorageConfiguration() instanceof YamlJobEventCallerConfiguration);\n        YamlJobEventCallerConfiguration result = (YamlJobEventCallerConfiguration) actual.getTracingStorageConfiguration();\n        assertThat(result.getTracingStorageFixture(), is(expectedStorage));\n    }\n}\n"
  },
  {
    "path": "kernel/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.kernel.executor.error.handler.fixture.FooJobErrorHandlerFixture\norg.apache.shardingsphere.elasticjob.kernel.executor.error.handler.fixture.BarJobErrorHandlerFixture"
  },
  {
    "path": "kernel/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.kernel.fixture.executor.ClassedFooJobExecutor\n"
  },
  {
    "path": "kernel/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.TypedJobItemExecutor",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.kernel.fixture.executor.TypedFooJobExecutor\n"
  },
  {
    "path": "kernel/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.kernel.listener.fixture.TestDistributeOnceElasticJobListener\norg.apache.shardingsphere.elasticjob.kernel.listener.fixture.TestElasticJobListener\n"
  },
  {
    "path": "kernel/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListenerFactory",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.kernel.tracing.fixture.listener.TracingListenerFixtureFactory\n"
  },
  {
    "path": "kernel/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfigurationConverter",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.kernel.tracing.fixture.config.TracingStorageFixtureConfigurationConverter\n"
  },
  {
    "path": "kernel/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfigurationConverter",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlJobEventCallerConfigurationConverter\n"
  },
  {
    "path": "kernel/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n            <level>ERROR</level>\n        </filter>\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService\" level=\"OFF\" />\n    <logger name=\"org.apache.shardingsphere.elasticjob.kernel.tracing.event.JobTracingEventBus\" level=\"OFF\" />\n    <logger name=\"org.apache.curator.framework.listen.MappingListenerManager\" level=\"OFF\" />\n</configuration>\n"
  },
  {
    "path": "lifecycle/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-lifecycle</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-bootstrap</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-registry-center-zookeeper-curator</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-test-util</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/api/JobAPIFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.api;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.operate.JobOperateAPIImpl;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.operate.ShardingOperateAPIImpl;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.reg.RegistryCenterFactory;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.settings.JobConfigurationAPIImpl;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.JobStatisticsAPIImpl;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.ServerStatisticsAPIImpl;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.ShardingStatisticsAPIImpl;\n\n/**\n * Job API factory.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class JobAPIFactory {\n    \n    /**\n     * Create job configuration API.\n     *\n     * @param connectString registry center connect string\n     * @param namespace registry center namespace\n     * @param digest registry center digest\n     * @return job configuration API\n     */\n    public static JobConfigurationAPI createJobConfigurationAPI(final String connectString, final String namespace, final String digest) {\n        return new JobConfigurationAPIImpl(RegistryCenterFactory.createCoordinatorRegistryCenter(connectString, namespace, digest));\n    }\n    \n    /**\n     * Create job operate API.\n     *\n     * @param connectString registry center connect string\n     * @param namespace registry center namespace\n     * @param digest registry center digest\n     * @return job operate API\n     */\n    public static JobOperateAPI createJobOperateAPI(final String connectString, final String namespace, final String digest) {\n        return new JobOperateAPIImpl(RegistryCenterFactory.createCoordinatorRegistryCenter(connectString, namespace, digest));\n    }\n    \n    /**\n     * Create job sharding operate API.\n     *\n     * @param connectString registry center connect string\n     * @param namespace registry center namespace\n     * @param digest registry center digest\n     * @return job sharding operate API\n     */\n    public static ShardingOperateAPI createShardingOperateAPI(final String connectString, final String namespace, final String digest) {\n        return new ShardingOperateAPIImpl(RegistryCenterFactory.createCoordinatorRegistryCenter(connectString, namespace, digest));\n    }\n    \n    /**\n     * Create job statistics API.\n     *\n     * @param connectString registry center connect string\n     * @param namespace registry center namespace\n     * @param digest registry center digest\n     * @return job statistics API\n     */\n    public static JobStatisticsAPI createJobStatisticsAPI(final String connectString, final String namespace, final String digest) {\n        return new JobStatisticsAPIImpl(RegistryCenterFactory.createCoordinatorRegistryCenter(connectString, namespace, digest));\n    }\n    \n    /**\n     * Create server statistics API.\n     *\n     * @param connectString registry center connect string\n     * @param namespace registry center namespace\n     * @param digest registry center digest\n     * @return job server statistics API\n     */\n    public static ServerStatisticsAPI createServerStatisticsAPI(final String connectString, final String namespace, final String digest) {\n        return new ServerStatisticsAPIImpl(RegistryCenterFactory.createCoordinatorRegistryCenter(connectString, namespace, digest));\n    }\n    \n    /**\n     * Create sharding statistics API.\n     *\n     * @param connectString registry center connect string\n     * @param namespace registry center namespace\n     * @param digest registry center digest\n     * @return job sharding statistics API\n     */\n    public static ShardingStatisticsAPI createShardingStatisticsAPI(final String connectString, final String namespace, final String digest) {\n        return new ShardingStatisticsAPIImpl(RegistryCenterFactory.createCoordinatorRegistryCenter(connectString, namespace, digest));\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/api/JobConfigurationAPI.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.api;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\n\n/**\n * Job configuration API.\n */\npublic interface JobConfigurationAPI {\n    \n    /**\n     * Get job configuration.\n     *\n     * @param jobName job name\n     * @return job configuration\n     */\n    JobConfigurationPOJO getJobConfiguration(String jobName);\n    \n    /**\n     * Update job configuration.\n     *\n     * @param jobConfig job configuration\n     */\n    void updateJobConfiguration(JobConfigurationPOJO jobConfig);\n    \n    /**\n     * Remove job configuration.\n     *\n     * @param jobName job name\n     */\n    void removeJobConfiguration(String jobName);\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/api/JobOperateAPI.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.api;\n\nimport java.io.IOException;\n\n/**\n * Job operate API.\n */\npublic interface JobOperateAPI {\n    \n    /**\n     * Trigger job to run at once.\n     *\n     * <p>Job will not start until it does not conflict with the last running job, and this tag will be automatically cleaned up after it starts.</p>\n     *\n     * @param jobName job name\n     */\n    void trigger(String jobName);\n    \n    /**\n     * Disable job.\n     * \n     * <p>Will cause resharding.</p>\n     *\n     * @param jobName job name\n     * @param serverIp server IP address\n     */\n    void disable(String jobName, String serverIp);\n    \n    /**\n     * Enable job.\n     * \n     * @param jobName job name\n     * @param serverIp server IP address\n     */\n    void enable(String jobName, String serverIp);\n    \n    /**\n     * Shutdown Job.\n     *\n     * @param jobName job name\n     * @param serverIp server IP address\n     */\n    void shutdown(String jobName, String serverIp);\n    \n    /**\n     * Remove job.\n     * \n     * @param jobName job name\n     * @param serverIp server IP address\n     */\n    void remove(String jobName, String serverIp);\n    \n    /**\n     * Dump job.\n     *\n     * @param jobName job name\n     * @param instanceIp instance IP address\n     * @param dumpPort dump port\n     * @return dump job result\n     * @throws IOException i/o exception\n     */\n    String dump(String jobName, String instanceIp, int dumpPort) throws IOException;\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/api/JobStatisticsAPI.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.api;\n\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.JobBriefInfo;\n\nimport java.util.Collection;\n\n/**\n * Job statistics API.\n */\npublic interface JobStatisticsAPI {\n    \n    /**\n     * Get jobs total count.\n     *\n     * @return jobs total count.\n     */\n    int getJobsTotalCount();\n    \n    /**\n     * Get all jobs brief info.\n     *\n     * @return all jobs brief info.\n     */\n    Collection<JobBriefInfo> getAllJobsBriefInfo();\n    \n    /**\n     * Get job brief info.\n     *\n     * @param jobName job name\n     * @return job brief info\n     */\n    JobBriefInfo getJobBriefInfo(String jobName);\n    \n    /**\n     * Get jobs brief info.\n     *\n     * @param ip server IP address\n     * @return jobs brief info\n     */\n    Collection<JobBriefInfo> getJobsBriefInfo(String ip);\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/api/ServerStatisticsAPI.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.api;\n\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.ServerBriefInfo;\n\nimport java.util.Collection;\n\n/**\n * Server statistics API.\n */\npublic interface ServerStatisticsAPI {\n    \n    /**\n     * Get servers total count.\n     *\n     * @return servers total count\n     */\n    int getServersTotalCount();\n    \n    /**\n     * Get all servers brief info.\n     *\n     * @return all servers brief info\n     */\n    Collection<ServerBriefInfo> getAllServersBriefInfo();\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/api/ShardingOperateAPI.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.api;\n\n/**\n * Sharding operate API.\n */\npublic interface ShardingOperateAPI {\n    \n    /**\n     * Disable job sharding item.\n     * \n     * @param jobName job name\n     * @param item sharding item\n     */\n    void disable(String jobName, String item);\n    \n    /**\n     * Enable job sharding item.\n     *\n     * @param jobName job name\n     * @param item sharding item\n     */\n    void enable(String jobName, String item);\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/api/ShardingStatisticsAPI.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.api;\n\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.ShardingInfo;\n\nimport java.util.Collection;\n\n/**\n * Sharding statistics API.\n */\npublic interface ShardingStatisticsAPI {\n    \n    /**\n     * Get sharding info.\n     *\n     * @param jobName job name\n     * @return sharding info of job\n     */\n    Collection<ShardingInfo> getShardingInfo(String jobName);\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/domain/JobBriefInfo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.domain;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport java.io.Serializable;\n\n/**\n * Job brief info.\n */\n@Getter\n@Setter\npublic final class JobBriefInfo implements Serializable, Comparable<JobBriefInfo> {\n    \n    private static final long serialVersionUID = 8405751873086755148L;\n    \n    private String jobName;\n    \n    private JobStatus status;\n    \n    private String description;\n    \n    private String cron;\n    \n    private int instanceCount;\n    \n    private int shardingTotalCount;\n    \n    @Override\n    public int compareTo(final JobBriefInfo o) {\n        return getJobName().compareTo(o.getJobName());\n    }\n    \n    /**\n     * Job status.\n     */\n    public enum JobStatus {\n        OK,\n        CRASHED,\n        DISABLED,\n        SHARDING_FLAG\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/domain/ServerBriefInfo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.domain;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.Setter;\n\nimport java.io.Serializable;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Server brief info.\n */\n@RequiredArgsConstructor\n@Getter\n@Setter\npublic final class ServerBriefInfo implements Serializable, Comparable<ServerBriefInfo> {\n    \n    private static final long serialVersionUID = 1133149706443681483L;\n    \n    private final String serverIp;\n    \n    private final Set<String> instances = new HashSet<>();\n    \n    private final Set<String> jobNames = new HashSet<>();\n    \n    private int instancesNum;\n    \n    private int jobsNum;\n    \n    private AtomicInteger disabledJobsNum = new AtomicInteger();\n    \n    @Override\n    public int compareTo(final ServerBriefInfo o) {\n        return (getServerIp()).compareTo(o.getServerIp());\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/domain/ShardingInfo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.domain;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport java.io.Serializable;\n\n/**\n * Job sharding info.\n */\n@Getter\n@Setter\npublic final class ShardingInfo implements Serializable, Comparable<ShardingInfo> {\n    \n    private static final long serialVersionUID = 8587397581949456718L;\n    \n    private int item;\n    \n    private String serverIp;\n    \n    private String instanceId;\n    \n    private ShardingStatus status;\n    \n    private boolean failover;\n    \n    @Override\n    public int compareTo(final ShardingInfo o) {\n        return getItem() - o.getItem();\n    }\n    \n    /**\n     * Job sharding status.\n     */\n    public enum ShardingStatus {\n        \n        DISABLED,\n        RUNNING,\n        SHARDING_FLAG,\n        PENDING;\n        \n        /**\n         * Get sharding status.\n         * \n         * @param isDisabled is disabled \n         * @param isRunning is running\n         * @param isShardingFlag is need to Sharding\n         * @return job sharding status\n         */\n        public static ShardingStatus getShardingStatus(final boolean isDisabled, final boolean isRunning, final boolean isShardingFlag) {\n            if (isDisabled) {\n                return DISABLED;\n            }\n            if (isRunning) {\n                return RUNNING;\n            }\n            if (isShardingFlag) {\n                return SHARDING_FLAG;\n            }\n            return PENDING;\n        }\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/operate/JobOperateAPIImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.operate;\n\nimport com.google.common.base.Preconditions;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerStatus;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.JobOperateAPI;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.io.IOException;\nimport java.util.List;\n\n/**\n * Job operate API implementation class.\n */\npublic final class JobOperateAPIImpl implements JobOperateAPI {\n    \n    private final CoordinatorRegistryCenter regCenter;\n    \n    public JobOperateAPIImpl(final CoordinatorRegistryCenter regCenter) {\n        this.regCenter = regCenter;\n    }\n    \n    @Override\n    public void trigger(final String jobName) {\n        Preconditions.checkNotNull(jobName, \"Job name cannot be null\");\n        new InstanceService(regCenter, jobName).triggerAllInstances();\n    }\n    \n    @Override\n    public void disable(final String jobName, final String serverIp) {\n        disableOrEnableJobs(jobName, serverIp, true);\n    }\n    \n    @Override\n    public void enable(final String jobName, final String serverIp) {\n        disableOrEnableJobs(jobName, serverIp, false);\n    }\n    \n    private void disableOrEnableJobs(final String jobName, final String serverIp, final boolean disabled) {\n        Preconditions.checkArgument(null != jobName || null != serverIp, \"At least indicate jobName or serverIp.\");\n        if (null != jobName && null != serverIp) {\n            persistDisabledOrEnabledJob(jobName, serverIp, disabled);\n        } else if (null != jobName) {\n            JobNodePath jobNodePath = new JobNodePath(jobName);\n            for (String each : regCenter.getChildrenKeys(jobNodePath.getServerNodePath())) {\n                if (disabled) {\n                    regCenter.persist(jobNodePath.getServerNodePath(each), ServerStatus.DISABLED.name());\n                } else {\n                    regCenter.persist(jobNodePath.getServerNodePath(each), ServerStatus.ENABLED.name());\n                }\n            }\n        } else {\n            List<String> jobNames = regCenter.getChildrenKeys(\"/\");\n            for (String each : jobNames) {\n                if (regCenter.isExisted(new JobNodePath(each).getServerNodePath(serverIp))) {\n                    persistDisabledOrEnabledJob(each, serverIp, disabled);\n                }\n            }\n        }\n    }\n    \n    private void persistDisabledOrEnabledJob(final String jobName, final String serverIp, final boolean disabled) {\n        JobNodePath jobNodePath = new JobNodePath(jobName);\n        String serverNodePath = jobNodePath.getServerNodePath(serverIp);\n        if (disabled) {\n            regCenter.persist(serverNodePath, ServerStatus.DISABLED.name());\n        } else {\n            regCenter.persist(serverNodePath, ServerStatus.ENABLED.name());\n        }\n    }\n    \n    @Override\n    public void shutdown(final String jobName, final String serverIp) {\n        Preconditions.checkArgument(null != jobName || null != serverIp, \"At least indicate jobName or serverIp.\");\n        if (null != jobName && null != serverIp) {\n            JobNodePath jobNodePath = new JobNodePath(jobName);\n            for (String each : regCenter.getChildrenKeys(jobNodePath.getInstancesNodePath())) {\n                JobInstance jobInstance = YamlEngine.unmarshal(regCenter.get(jobNodePath.getInstanceNodePath(each)), JobInstance.class);\n                if (serverIp.equals(jobInstance.getServerIp())) {\n                    regCenter.remove(jobNodePath.getInstanceNodePath(each));\n                }\n            }\n        } else if (null != jobName) {\n            JobNodePath jobNodePath = new JobNodePath(jobName);\n            for (String each : regCenter.getChildrenKeys(jobNodePath.getInstancesNodePath())) {\n                regCenter.remove(jobNodePath.getInstanceNodePath(each));\n            }\n        } else {\n            List<String> jobNames = regCenter.getChildrenKeys(\"/\");\n            for (String job : jobNames) {\n                JobNodePath jobNodePath = new JobNodePath(job);\n                List<String> instances = regCenter.getChildrenKeys(jobNodePath.getInstancesNodePath());\n                for (String each : instances) {\n                    JobInstance jobInstance = YamlEngine.unmarshal(regCenter.get(jobNodePath.getInstanceNodePath(each)), JobInstance.class);\n                    if (serverIp.equals(jobInstance.getServerIp())) {\n                        regCenter.remove(jobNodePath.getInstanceNodePath(each));\n                    }\n                }\n            }\n        }\n    }\n    \n    @Override\n    public void remove(final String jobName, final String serverIp) {\n        shutdown(jobName, serverIp);\n        if (null != jobName && null != serverIp) {\n            regCenter.remove(new JobNodePath(jobName).getServerNodePath(serverIp));\n        } else if (null != jobName) {\n            JobNodePath jobNodePath = new JobNodePath(jobName);\n            List<String> servers = regCenter.getChildrenKeys(jobNodePath.getServerNodePath());\n            for (String each : servers) {\n                regCenter.remove(jobNodePath.getServerNodePath(each));\n            }\n        } else if (null != serverIp) {\n            List<String> jobNames = regCenter.getChildrenKeys(\"/\");\n            for (String each : jobNames) {\n                regCenter.remove(new JobNodePath(each).getServerNodePath(serverIp));\n            }\n        }\n    }\n    \n    @Override\n    public String dump(final String jobName, final String instanceIp, final int dumpPort) throws IOException {\n        return SnapshotService.dumpJob(instanceIp, dumpPort, jobName);\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/operate/ShardingOperateAPIImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.operate;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.ShardingOperateAPI;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\n/**\n * Sharding operate API implementation class.\n */\npublic final class ShardingOperateAPIImpl implements ShardingOperateAPI {\n    \n    private final CoordinatorRegistryCenter regCenter;\n    \n    public ShardingOperateAPIImpl(final CoordinatorRegistryCenter regCenter) {\n        this.regCenter = regCenter;\n    }\n    \n    @Override\n    public void disable(final String jobName, final String item) {\n        disableOrEnableJobs(jobName, item, true);\n    }\n    \n    @Override\n    public void enable(final String jobName, final String item) {\n        disableOrEnableJobs(jobName, item, false);\n    }\n    \n    private void disableOrEnableJobs(final String jobName, final String item, final boolean disabled) {\n        JobNodePath jobNodePath = new JobNodePath(jobName);\n        String shardingDisabledNodePath = jobNodePath.getShardingNodePath(item, \"disabled\");\n        if (disabled) {\n            regCenter.persist(shardingDisabledNodePath, \"\");\n        } else {\n            regCenter.remove(shardingDisabledNodePath);\n        }\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/reg/RegistryCenterFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.reg;\n\nimport com.google.common.base.Strings;\nimport com.google.common.hash.HashCode;\nimport com.google.common.hash.Hasher;\nimport com.google.common.hash.Hashing;\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Registry center factory.\n */\n@SuppressWarnings(\"UnstableApiUsage\")\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class RegistryCenterFactory {\n    \n    private static final Map<HashCode, CoordinatorRegistryCenter> REG_CENTER_REGISTRY = new ConcurrentHashMap<>();\n    \n    /**\n     * Create a {@link CoordinatorRegistryCenter} or return the existing one if there is one set up with the same {@code connectionString}, {@code namespace} and {@code digest} already.\n     *\n     * @param connectString registry center connect string\n     * @param namespace registry center namespace\n     * @param digest registry center digest\n     * @return registry center\n     */\n    public static CoordinatorRegistryCenter createCoordinatorRegistryCenter(final String connectString, final String namespace, final String digest) {\n        Hasher hasher = Hashing.sha256().newHasher().putString(connectString, StandardCharsets.UTF_8).putString(namespace, StandardCharsets.UTF_8);\n        if (!Strings.isNullOrEmpty(digest)) {\n            hasher.putString(digest, StandardCharsets.UTF_8);\n        }\n        HashCode hashCode = hasher.hash();\n        return REG_CENTER_REGISTRY.computeIfAbsent(hashCode, unused -> {\n            CoordinatorRegistryCenter result = newCoordinatorRegistryCenter(connectString, namespace, digest);\n            result.init();\n            return result;\n        });\n    }\n    \n    private static CoordinatorRegistryCenter newCoordinatorRegistryCenter(final String connectString,\n                                                                          final String namespace,\n                                                                          final String digest) {\n        final ZookeeperConfiguration zkConfig = new ZookeeperConfiguration(connectString, namespace);\n        if (!Strings.isNullOrEmpty(digest)) {\n            zkConfig.setDigest(digest);\n        }\n        return new ZookeeperRegistryCenter(zkConfig);\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/settings/JobConfigurationAPIImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.settings;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.JobConfigurationAPI;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\n\n/**\n * Job Configuration API implementation class.\n */\n@RequiredArgsConstructor\npublic final class JobConfigurationAPIImpl implements JobConfigurationAPI {\n    \n    private final CoordinatorRegistryCenter regCenter;\n    \n    @Override\n    public JobConfigurationPOJO getJobConfiguration(final String jobName) {\n        String yamlContent = regCenter.get(new JobNodePath(jobName).getConfigNodePath());\n        if (null == yamlContent) {\n            return null;\n        }\n        return YamlEngine.unmarshal(yamlContent, JobConfigurationPOJO.class);\n    }\n    \n    @Override\n    public void updateJobConfiguration(final JobConfigurationPOJO jobConfig) {\n        Preconditions.checkArgument(!Strings.isNullOrEmpty(jobConfig.getJobName()), \"jobName can not be empty.\");\n        Preconditions.checkArgument(jobConfig.getShardingTotalCount() > 0, \"shardingTotalCount should larger than zero.\");\n        JobNodePath jobNodePath = new JobNodePath(jobConfig.getJobName());\n        regCenter.update(jobNodePath.getConfigNodePath(), YamlEngine.marshal(jobConfig));\n    }\n    \n    @Override\n    public void removeJobConfiguration(final String jobName) {\n        regCenter.remove(\"/\" + jobName);\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/statistics/JobStatisticsAPIImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.statistics;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.JobStatisticsAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.JobBriefInfo;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Job statistics API implementation class.\n */\n@RequiredArgsConstructor\npublic final class JobStatisticsAPIImpl implements JobStatisticsAPI {\n    \n    private final CoordinatorRegistryCenter regCenter;\n    \n    @Override\n    public int getJobsTotalCount() {\n        return regCenter.getChildrenKeys(\"/\").size();\n    }\n    \n    @Override\n    public Collection<JobBriefInfo> getAllJobsBriefInfo() {\n        List<String> jobNames = regCenter.getChildrenKeys(\"/\");\n        List<JobBriefInfo> result = new ArrayList<>(jobNames.size());\n        for (String each : jobNames) {\n            JobBriefInfo jobBriefInfo = getJobBriefInfo(each);\n            if (null != jobBriefInfo) {\n                result.add(jobBriefInfo);\n            }\n        }\n        Collections.sort(result);\n        return result;\n    }\n    \n    @Override\n    public JobBriefInfo getJobBriefInfo(final String jobName) {\n        JobNodePath jobNodePath = new JobNodePath(jobName);\n        JobBriefInfo result = new JobBriefInfo();\n        result.setJobName(jobName);\n        String jobConfigYaml = regCenter.get(jobNodePath.getConfigNodePath());\n        if (null == jobConfigYaml) {\n            return null;\n        }\n        JobConfiguration jobConfig = YamlEngine.unmarshal(jobConfigYaml, JobConfigurationPOJO.class).toJobConfiguration();\n        result.setDescription(jobConfig.getDescription());\n        result.setCron(jobConfig.getCron());\n        result.setInstanceCount(getJobInstanceCount(jobName));\n        result.setShardingTotalCount(jobConfig.getShardingTotalCount());\n        result.setStatus(getJobStatus(jobName));\n        return result;\n    }\n    \n    private JobBriefInfo.JobStatus getJobStatus(final String jobName) {\n        JobNodePath jobNodePath = new JobNodePath(jobName);\n        List<String> instances = regCenter.getChildrenKeys(jobNodePath.getInstancesNodePath());\n        if (instances.isEmpty()) {\n            return JobBriefInfo.JobStatus.CRASHED;\n        }\n        if (isAllDisabled(jobNodePath)) {\n            return JobBriefInfo.JobStatus.DISABLED;\n        }\n        if (isHasShardingFlag(jobNodePath, instances)) {\n            return JobBriefInfo.JobStatus.SHARDING_FLAG;\n        }\n        return JobBriefInfo.JobStatus.OK;\n    }\n    \n    private boolean isAllDisabled(final JobNodePath jobNodePath) {\n        List<String> serversPath = regCenter.getChildrenKeys(jobNodePath.getServerNodePath());\n        int disabledServerCount = 0;\n        for (String each : serversPath) {\n            if (JobBriefInfo.JobStatus.DISABLED.name().equals(regCenter.get(jobNodePath.getServerNodePath(each)))) {\n                disabledServerCount++;\n            }\n        }\n        return disabledServerCount == serversPath.size();\n    }\n    \n    private boolean isHasShardingFlag(final JobNodePath jobNodePath, final List<String> instances) {\n        Set<String> shardingInstances = new HashSet<>();\n        for (String each : regCenter.getChildrenKeys(jobNodePath.getShardingNodePath())) {\n            String instanceId = regCenter.get(jobNodePath.getShardingNodePath(each, \"instance\"));\n            if (null != instanceId && !instanceId.isEmpty()) {\n                shardingInstances.add(instanceId);\n            }\n        }\n        return !new HashSet<>(instances).containsAll(shardingInstances) || shardingInstances.isEmpty();\n    }\n    \n    private int getJobInstanceCount(final String jobName) {\n        return regCenter.getChildrenKeys(new JobNodePath(jobName).getInstancesNodePath()).size();\n    }\n    \n    @Override\n    public Collection<JobBriefInfo> getJobsBriefInfo(final String ip) {\n        List<String> jobNames = regCenter.getChildrenKeys(\"/\");\n        List<JobBriefInfo> result = new ArrayList<>(jobNames.size());\n        for (String each : jobNames) {\n            JobBriefInfo jobBriefInfo = getJobBriefInfoByJobNameAndIp(each, ip);\n            if (null != jobBriefInfo) {\n                result.add(jobBriefInfo);\n            }\n        }\n        Collections.sort(result);\n        return result;\n    }\n    \n    private JobBriefInfo getJobBriefInfoByJobNameAndIp(final String jobName, final String ip) {\n        if (!regCenter.isExisted(new JobNodePath(jobName).getServerNodePath(ip))) {\n            return null;\n        }\n        JobBriefInfo result = new JobBriefInfo();\n        result.setJobName(jobName);\n        result.setStatus(getJobStatusByJobNameAndIp(jobName, ip));\n        result.setInstanceCount(getJobInstanceCountByJobNameAndIP(jobName, ip));\n        return result;\n    }\n    \n    private JobBriefInfo.JobStatus getJobStatusByJobNameAndIp(final String jobName, final String ip) {\n        JobNodePath jobNodePath = new JobNodePath(jobName);\n        String status = regCenter.get(jobNodePath.getServerNodePath(ip));\n        if (\"DISABLED\".equalsIgnoreCase(status)) {\n            return JobBriefInfo.JobStatus.DISABLED;\n        } else {\n            return JobBriefInfo.JobStatus.OK;\n        }\n    }\n    \n    private int getJobInstanceCountByJobNameAndIP(final String jobName, final String ip) {\n        int result = 0;\n        JobNodePath jobNodePath = new JobNodePath(jobName);\n        List<String> instances = regCenter.getChildrenKeys(jobNodePath.getInstancesNodePath());\n        for (String each : instances) {\n            JobInstance jobInstance = YamlEngine.unmarshal(regCenter.get(jobNodePath.getInstanceNodePath(each)), JobInstance.class);\n            if (ip.equals(jobInstance.getServerIp())) {\n                result++;\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/statistics/ServerStatisticsAPIImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.statistics;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.ServerStatisticsAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.ServerBriefInfo;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Server statistics API implementation class.\n */\n@RequiredArgsConstructor\npublic final class ServerStatisticsAPIImpl implements ServerStatisticsAPI {\n    \n    private final CoordinatorRegistryCenter regCenter;\n    \n    @Override\n    public int getServersTotalCount() {\n        Set<String> servers = new HashSet<>();\n        for (String jobName : regCenter.getChildrenKeys(\"/\")) {\n            JobNodePath jobNodePath = new JobNodePath(jobName);\n            servers.addAll(regCenter.getChildrenKeys(jobNodePath.getServerNodePath()));\n        }\n        return servers.size();\n    }\n    \n    @Override\n    public Collection<ServerBriefInfo> getAllServersBriefInfo() {\n        ConcurrentHashMap<String, ServerBriefInfo> servers = new ConcurrentHashMap<>();\n        for (String jobName : regCenter.getChildrenKeys(\"/\")) {\n            JobNodePath jobNodePath = new JobNodePath(jobName);\n            for (String each : regCenter.getChildrenKeys(jobNodePath.getServerNodePath())) {\n                servers.putIfAbsent(each, new ServerBriefInfo(each));\n                ServerBriefInfo serverInfo = servers.get(each);\n                if (\"DISABLED\".equalsIgnoreCase(regCenter.get(jobNodePath.getServerNodePath(each)))) {\n                    serverInfo.getDisabledJobsNum().incrementAndGet();\n                }\n                serverInfo.getJobNames().add(jobName);\n                serverInfo.setJobsNum(serverInfo.getJobNames().size());\n            }\n            List<String> instances = regCenter.getChildrenKeys(jobNodePath.getInstancesNodePath());\n            for (String each : instances) {\n                JobInstance jobInstance = YamlEngine.unmarshal(regCenter.get(jobNodePath.getInstanceNodePath(each)), JobInstance.class);\n                if (null != jobInstance) {\n                    ServerBriefInfo serverInfo = servers.get(jobInstance.getServerIp());\n                    if (null != serverInfo) {\n                        serverInfo.getInstances().add(each);\n                        serverInfo.setInstancesNum(serverInfo.getInstances().size());\n                    }\n                }\n            }\n        }\n        List<ServerBriefInfo> result = new ArrayList<>(servers.values());\n        Collections.sort(result);\n        return result;\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/main/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/statistics/ShardingStatisticsAPIImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.statistics;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.storage.JobNodePath;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.ShardingStatisticsAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.ShardingInfo;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Sharding statistics API implementation class.\n */\n@RequiredArgsConstructor\npublic final class ShardingStatisticsAPIImpl implements ShardingStatisticsAPI {\n    \n    private final CoordinatorRegistryCenter regCenter;\n    \n    @Override\n    public Collection<ShardingInfo> getShardingInfo(final String jobName) {\n        String shardingRootPath = new JobNodePath(jobName).getShardingNodePath();\n        List<String> items = regCenter.getChildrenKeys(shardingRootPath);\n        List<ShardingInfo> result = new ArrayList<>(items.size());\n        for (String each : items) {\n            result.add(getShardingInfo(jobName, each));\n        }\n        Collections.sort(result);\n        return result;\n    }\n    \n    private ShardingInfo getShardingInfo(final String jobName, final String item) {\n        ShardingInfo result = new ShardingInfo();\n        result.setItem(Integer.parseInt(item));\n        JobNodePath jobNodePath = new JobNodePath(jobName);\n        String instanceId = regCenter.get(jobNodePath.getShardingNodePath(item, \"instance\"));\n        boolean disabled = regCenter.isExisted(jobNodePath.getShardingNodePath(item, \"disabled\"));\n        boolean running = regCenter.isExisted(jobNodePath.getShardingNodePath(item, \"running\"));\n        boolean shardingError = !regCenter.isExisted(jobNodePath.getInstanceNodePath(instanceId));\n        result.setStatus(ShardingInfo.ShardingStatus.getShardingStatus(disabled, running, shardingError));\n        result.setFailover(regCenter.isExisted(jobNodePath.getShardingNodePath(item, \"failover\")));\n        if (null != instanceId) {\n            JobInstance jobInstance = YamlEngine.unmarshal(regCenter.get(jobNodePath.getInstanceNodePath(instanceId)), JobInstance.class);\n            result.setServerIp(jobInstance.getServerIp());\n            result.setInstanceId(jobInstance.getJobInstanceId());\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/test/java/org/apache/shardingsphere/elasticjob/lifecycle/api/JobAPIFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.api;\n\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.instanceOf;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass JobAPIFactoryTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    @BeforeAll\n    static void setUp() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @Test\n    void assertCreateJobConfigAPI() {\n        assertThat(JobAPIFactory.createJobConfigurationAPI(EMBED_TESTING_SERVER.getConnectionString(), \"namespace\", null), instanceOf(JobConfigurationAPI.class));\n    }\n    \n    @Test\n    void assertCreateJobOperateAPI() {\n        assertThat(JobAPIFactory.createJobOperateAPI(EMBED_TESTING_SERVER.getConnectionString(), \"namespace\", null), instanceOf(JobOperateAPI.class));\n    }\n    \n    @Test\n    void assertCreateServerOperateAPI() {\n        assertThat(JobAPIFactory.createShardingOperateAPI(EMBED_TESTING_SERVER.getConnectionString(), \"namespace\", null), instanceOf(ShardingOperateAPI.class));\n    }\n    \n    @Test\n    void assertCreateJobStatisticsAPI() {\n        assertThat(JobAPIFactory.createJobStatisticsAPI(EMBED_TESTING_SERVER.getConnectionString(), \"namespace\", null), instanceOf(JobStatisticsAPI.class));\n    }\n    \n    @Test\n    void assertCreateServerStatisticsAPI() {\n        assertThat(JobAPIFactory.createServerStatisticsAPI(EMBED_TESTING_SERVER.getConnectionString(), \"namespace\", null), instanceOf(ServerStatisticsAPI.class));\n    }\n    \n    @Test\n    void assertCreateShardingStatisticsAPI() {\n        assertThat(JobAPIFactory.createShardingStatisticsAPI(EMBED_TESTING_SERVER.getConnectionString(), \"namespace\", null), instanceOf(ShardingStatisticsAPI.class));\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/test/java/org/apache/shardingsphere/elasticjob/lifecycle/domain/ShardingStatusTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.domain;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass ShardingStatusTest {\n    \n    @Test\n    void assertGetShardingStatusWhenIsDisabled() {\n        assertThat(ShardingInfo.ShardingStatus.getShardingStatus(true, false, true), is(ShardingInfo.ShardingStatus.DISABLED));\n    }\n    \n    @Test\n    void assertGetShardingStatusWhenIsRunning() {\n        assertThat(ShardingInfo.ShardingStatus.getShardingStatus(false, true, false), is(ShardingInfo.ShardingStatus.RUNNING));\n    }\n    \n    @Test\n    void assertGetShardingStatusWhenIsPending() {\n        assertThat(ShardingInfo.ShardingStatus.getShardingStatus(false, false, false), is(ShardingInfo.ShardingStatus.PENDING));\n    }\n    \n    @Test\n    void assertGetShardingStatusWhenIsShardingError() {\n        assertThat(ShardingInfo.ShardingStatus.getShardingStatus(false, false, true), is(ShardingInfo.ShardingStatus.SHARDING_FLAG));\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/test/java/org/apache/shardingsphere/elasticjob/lifecycle/fixture/LifecycleYamlConstants.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.fixture;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class LifecycleYamlConstants {\n    \n    private static final String SIMPLE_JOB_YAML = \"jobName: %s\\n\"\n            + \"cron: 0/1 * * * * ?\\n\"\n            + \"shardingTotalCount: 3\\n\"\n            + \"jobParameter: param\\n\"\n            + \"monitorExecution: false\\n\"\n            + \"failover: true\\n\"\n            + \"misfire: false\\n\"\n            + \"maxTimeDiffSeconds: 100\\n\"\n            + \"jobShardingStrategyType: AVG_ALLOCATION\\n\"\n            + \"description: %s\\n\"\n            + \"disabled: false\\n\"\n            + \"overwrite: false\\n\";\n    \n    private static final String DATAFLOW_JOB_YAML = \"cron: 0/1 * * * * ?\\n\"\n            + \"description: ''\\n\"\n            + \"disabled: false\\n\"\n            + \"failover: false\\n\"\n            + \"jobName: test_job\\n\"\n            + \"jobParameter: param\\n\"\n            + \"maxTimeDiffSeconds: -1\\n\"\n            + \"misfire: true\\n\"\n            + \"monitorExecution: true\\n\"\n            + \"overwrite: false\\n\"\n            + \"props:\\n\"\n            + \"  streaming.process: 'true'\\n\"\n            + \"reconcileIntervalMinutes: 10\\n\"\n            + \"shardingTotalCount: 3\\n\"\n            + \"staticSharding: false\\n\";\n    \n    private static final String SCRIPT_JOB_YAML = \"jobName: test_job\\n\"\n            + \"cron: 0/1 * * * * ?\\n\"\n            + \"shardingTotalCount: 3\\n\"\n            + \"jobParameter: param\\n\"\n            + \"monitorExecution: true\\n\"\n            + \"failover: false\\n\"\n            + \"misfire: true\\n\"\n            + \"maxTimeDiffSeconds: -1\\n\"\n            + \"reconcileIntervalMinutes: 10\\n\"\n            + \"description: ''\\n\"\n            + \"props:\\n\"\n            + \"  script.command.line: echo\\n\"\n            + \"disabled: false\\n\"\n            + \"overwrite: false\\n\";\n    \n    /**\n     * Get the config of simple job in YAML format.\n     *\n     * @param jobName name of the job\n     * @param desc description of the job\n     * @return the string of job config\n     */\n    public static String getSimpleJobYaml(final String jobName, final String desc) {\n        return String.format(SIMPLE_JOB_YAML, jobName, desc);\n    }\n    \n    /**\n     * Get the config of dataflow job in YAML format.\n     *\n     * @return the string of job config\n     */\n    public static String getDataflowJobYaml() {\n        return DATAFLOW_JOB_YAML;\n    }\n    \n    /**\n     * Get the config of script job in YAML format.\n     *\n     * @return the string of job config\n     */\n    public static String getScriptJobYaml() {\n        return SCRIPT_JOB_YAML;\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/test/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/operate/JobOperateAPIImplTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.operate;\n\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.JobOperateAPI;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass JobOperateAPIImplTest {\n    \n    private JobOperateAPI jobOperateAPI;\n    \n    // TODO We should not use `Mock.Strictness.LENIENT` here, but the default. This is a flaw in the unit test design.\n    @Mock(strictness = Mock.Strictness.LENIENT)\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeEach\n    void setUp() {\n        jobOperateAPI = new JobOperateAPIImpl(regCenter);\n    }\n    \n    @Test\n    void assertTriggerWithJobName() {\n        when(regCenter.isExisted(\"/test_job\")).thenReturn(true);\n        when(regCenter.isExisted(\"/test_job/trigger/ip1@-@defaultInstance\")).thenReturn(false);\n        when(regCenter.isExisted(\"/test_job/trigger/ip2@-@defaultInstance\")).thenReturn(false);\n        when(regCenter.getChildrenKeys(\"/test_job/instances\")).thenReturn(Arrays.asList(\"ip1@-@defaultInstance\", \"ip2@-@defaultInstance\"));\n        jobOperateAPI.trigger(\"test_job\");\n        verify(regCenter).getChildrenKeys(\"/test_job/instances\");\n        verify(regCenter).persist(\"/test_job/trigger/ip1@-@defaultInstance\", \"\");\n        verify(regCenter).persist(\"/test_job/trigger/ip2@-@defaultInstance\", \"\");\n    }\n    \n    @Test\n    void assertDisableWithJobNameAndServerIp() {\n        jobOperateAPI.disable(\"test_job\", \"localhost\");\n        verify(regCenter).persist(\"/test_job/servers/localhost\", \"DISABLED\");\n    }\n    \n    @Test\n    void assertDisableWithJobName() {\n        when(regCenter.getChildrenKeys(\"/test_job/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        jobOperateAPI.disable(\"test_job\", null);\n        verify(regCenter).getChildrenKeys(\"/test_job/servers\");\n        verify(regCenter).persist(\"/test_job/servers/ip1\", \"DISABLED\");\n        verify(regCenter).persist(\"/test_job/servers/ip2\", \"DISABLED\");\n    }\n    \n    @Test\n    void assertDisableWithServerIp() {\n        when(regCenter.getChildrenKeys(\"/\")).thenReturn(Arrays.asList(\"test_job1\", \"test_job2\"));\n        when(regCenter.isExisted(\"/test_job1/servers/localhost\")).thenReturn(true);\n        when(regCenter.isExisted(\"/test_job2/servers/localhost\")).thenReturn(true);\n        jobOperateAPI.disable(null, \"localhost\");\n        verify(regCenter).getChildrenKeys(\"/\");\n        verify(regCenter).persist(\"/test_job1/servers/localhost\", \"DISABLED\");\n        verify(regCenter).persist(\"/test_job2/servers/localhost\", \"DISABLED\");\n    }\n    \n    @Test\n    void assertEnableWithJobNameAndServerIp() {\n        jobOperateAPI.enable(\"test_job\", \"localhost\");\n        verify(regCenter).persist(\"/test_job/servers/localhost\", \"ENABLED\");\n    }\n    \n    @Test\n    void assertEnableWithJobName() {\n        when(regCenter.getChildrenKeys(\"/test_job/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        jobOperateAPI.enable(\"test_job\", null);\n        verify(regCenter).getChildrenKeys(\"/test_job/servers\");\n        verify(regCenter).persist(\"/test_job/servers/ip1\", \"ENABLED\");\n        verify(regCenter).persist(\"/test_job/servers/ip2\", \"ENABLED\");\n    }\n    \n    @Test\n    void assertEnableWithServerIp() {\n        when(regCenter.getChildrenKeys(\"/\")).thenReturn(Arrays.asList(\"test_job1\", \"test_job2\"));\n        when(regCenter.isExisted(\"/test_job1/servers/localhost\")).thenReturn(true);\n        when(regCenter.isExisted(\"/test_job2/servers/localhost\")).thenReturn(true);\n        jobOperateAPI.enable(null, \"localhost\");\n        verify(regCenter).getChildrenKeys(\"/\");\n        verify(regCenter).persist(\"/test_job1/servers/localhost\", \"ENABLED\");\n        verify(regCenter).persist(\"/test_job2/servers/localhost\", \"ENABLED\");\n    }\n    \n    @Test\n    void assertShutdownWithJobNameAndServerIp() {\n        when(regCenter.getChildrenKeys(\"/test_job/instances\")).thenReturn(Collections.singletonList(\"localhost@-@defaultInstance\"));\n        when(regCenter.get(\"/test_job/instances/localhost@-@defaultInstance\")).thenReturn(\"jobInstanceId: localhost@-@defaultInstance\\nserverIp: localhost\\n\");\n        jobOperateAPI.shutdown(\"test_job\", \"localhost\");\n        verify(regCenter).remove(\"/test_job/instances/localhost@-@defaultInstance\");\n    }\n    \n    @Test\n    void assertShutdownWithJobName() {\n        when(regCenter.getChildrenKeys(\"/test_job/instances\")).thenReturn(Arrays.asList(\"ip1@-@defaultInstance\", \"ip2@-@defaultInstance\"));\n        jobOperateAPI.shutdown(\"test_job\", null);\n        verify(regCenter).getChildrenKeys(\"/test_job/instances\");\n        verify(regCenter).remove(\"/test_job/instances/ip1@-@defaultInstance\");\n    }\n    \n    @Test\n    void assertShutdownWithServerIp() {\n        when(regCenter.getChildrenKeys(\"/\")).thenReturn(Arrays.asList(\"test_job1\", \"test_job2\"));\n        when(regCenter.getChildrenKeys(\"/test_job1/instances\")).thenReturn(Collections.singletonList(\"localhost@-@defaultInstance\"));\n        when(regCenter.getChildrenKeys(\"/test_job2/instances\")).thenReturn(Collections.singletonList(\"localhost@-@defaultInstance\"));\n        when(regCenter.get(\"/test_job1/instances/localhost@-@defaultInstance\")).thenReturn(\"jobInstanceId: localhost@-@defaultInstance\\nserverIp: localhost\\n\");\n        when(regCenter.get(\"/test_job2/instances/localhost@-@defaultInstance\")).thenReturn(\"jobInstanceId: localhost@-@defaultInstance\\nserverIp: localhost\\n\");\n        jobOperateAPI.shutdown(null, \"localhost\");\n        verify(regCenter).getChildrenKeys(\"/\");\n        verify(regCenter).remove(\"/test_job1/instances/localhost@-@defaultInstance\");\n        verify(regCenter).remove(\"/test_job2/instances/localhost@-@defaultInstance\");\n    }\n    \n    @Test\n    void assertRemoveWithJobNameAndServerIp() {\n        jobOperateAPI.remove(\"test_job\", \"ip1\");\n        verify(regCenter).remove(\"/test_job/servers/ip1\");\n        assertFalse(regCenter.isExisted(\"/test_job/servers/ip1\"));\n    }\n    \n    @Test\n    void assertRemoveWithJobName() {\n        when(regCenter.isExisted(\"/test_job\")).thenReturn(true);\n        when(regCenter.getChildrenKeys(\"/test_job/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        jobOperateAPI.remove(\"test_job\", null);\n        verify(regCenter).getChildrenKeys(\"/test_job/servers\");\n        verify(regCenter).remove(\"/test_job/servers/ip1\");\n        verify(regCenter).remove(\"/test_job/servers/ip2\");\n        assertFalse(regCenter.isExisted(\"/test_job/servers/ip1\"));\n        assertFalse(regCenter.isExisted(\"/test_job/servers/ip2\"));\n        assertTrue(regCenter.isExisted(\"/test_job\"));\n    }\n    \n    @Test\n    void assertRemoveWithServerIp() {\n        when(regCenter.getChildrenKeys(\"/\")).thenReturn(Arrays.asList(\"test_job1\", \"test_job2\"));\n        jobOperateAPI.remove(null, \"ip1\");\n        assertFalse(regCenter.isExisted(\"/test_job1/servers/ip1\"));\n        assertFalse(regCenter.isExisted(\"/test_job2/servers/ip1\"));\n    }\n    \n}\n"
  },
  {
    "path": "lifecycle/src/test/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/operate/ShardingOperateAPIImplTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.operate;\n\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.ShardingOperateAPI;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass ShardingOperateAPIImplTest {\n    \n    private ShardingOperateAPI shardingOperateAPI;\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeEach\n    void setUp() {\n        shardingOperateAPI = new ShardingOperateAPIImpl(regCenter);\n    }\n    \n    @Test\n    void assertDisableSharding() {\n        shardingOperateAPI.disable(\"test_job\", \"0\");\n        verify(regCenter).persist(\"/test_job/sharding/0/disabled\", \"\");\n    }\n    \n    @Test\n    void assertEnableSharding() {\n        shardingOperateAPI.enable(\"test_job\", \"0\");\n        verify(regCenter).remove(\"/test_job/sharding/0/disabled\");\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/test/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/reg/RegistryCenterFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.reg;\n\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport java.lang.reflect.Method;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass RegistryCenterFactoryTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    @BeforeAll\n    static void setUp() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @Test\n    void assertCreateCoordinatorRegistryCenterWithoutDigest() throws ReflectiveOperationException {\n        ZookeeperConfiguration zkConfig = getZookeeperConfiguration(RegistryCenterFactory.createCoordinatorRegistryCenter(EMBED_TESTING_SERVER.getConnectionString(), \"namespace\", null));\n        assertThat(zkConfig.getNamespace(), is(\"namespace\"));\n        assertNull(zkConfig.getDigest());\n    }\n    \n    @Test\n    void assertCreateCoordinatorRegistryCenterWithDigest() throws ReflectiveOperationException {\n        ZookeeperConfiguration zkConfig = getZookeeperConfiguration(RegistryCenterFactory.createCoordinatorRegistryCenter(EMBED_TESTING_SERVER.getConnectionString(), \"namespace\", \"digest\"));\n        assertThat(zkConfig.getNamespace(), is(\"namespace\"));\n        assertThat(zkConfig.getDigest(), is(\"digest\"));\n    }\n    \n    @Test\n    void assertCreateCoordinatorRegistryCenterFromCache() throws ReflectiveOperationException {\n        RegistryCenterFactory.createCoordinatorRegistryCenter(EMBED_TESTING_SERVER.getConnectionString(), \"otherNamespace\", null);\n        ZookeeperConfiguration zkConfig = getZookeeperConfiguration(RegistryCenterFactory.createCoordinatorRegistryCenter(EMBED_TESTING_SERVER.getConnectionString(), \"otherNamespace\", null));\n        assertThat(zkConfig.getNamespace(), is(\"otherNamespace\"));\n        assertNull(zkConfig.getDigest());\n    }\n    \n    private ZookeeperConfiguration getZookeeperConfiguration(final CoordinatorRegistryCenter regCenter) throws ReflectiveOperationException {\n        Method method = ZookeeperRegistryCenter.class.getDeclaredMethod(\"getZkConfig\");\n        method.setAccessible(true);\n        return (ZookeeperConfiguration) method.invoke(regCenter);\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/test/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/settings/JobConfigurationAPIImplTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.settings;\n\nimport org.apache.shardingsphere.elasticjob.dataflow.props.DataflowJobProperties;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.JobConfigurationAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.fixture.LifecycleYamlConstants;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.script.props.ScriptJobProperties;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\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;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass JobConfigurationAPIImplTest {\n    \n    private JobConfigurationAPI jobConfigAPI;\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeEach\n    void setUp() {\n        jobConfigAPI = new JobConfigurationAPIImpl(regCenter);\n    }\n    \n    @Test\n    void assertGetJobConfigNull() {\n        when(regCenter.get(\"/test_job/config\")).thenReturn(null);\n        JobConfigurationPOJO actual = jobConfigAPI.getJobConfiguration(\"test_job\");\n        assertNull(actual);\n        verify(regCenter).get(\"/test_job/config\");\n    }\n    \n    @Test\n    void assertGetDataflowJobConfig() {\n        when(regCenter.get(\"/test_job/config\")).thenReturn(LifecycleYamlConstants.getDataflowJobYaml());\n        JobConfigurationPOJO actual = jobConfigAPI.getJobConfiguration(\"test_job\");\n        assertJobConfig(actual);\n        assertThat(actual.getProps().getProperty(DataflowJobProperties.STREAM_PROCESS_KEY), is(\"true\"));\n        verify(regCenter).get(\"/test_job/config\");\n    }\n    \n    @Test\n    void assertGetScriptJobConfig() {\n        when(regCenter.get(\"/test_job/config\")).thenReturn(LifecycleYamlConstants.getScriptJobYaml());\n        JobConfigurationPOJO actual = jobConfigAPI.getJobConfiguration(\"test_job\");\n        assertJobConfig(actual);\n        assertThat(actual.getProps().getProperty(ScriptJobProperties.SCRIPT_KEY), is(\"echo\"));\n        verify(regCenter).get(\"/test_job/config\");\n    }\n    \n    private void assertJobConfig(final JobConfigurationPOJO pojo) {\n        assertThat(pojo.getJobName(), is(\"test_job\"));\n        assertThat(pojo.getShardingTotalCount(), is(3));\n        assertThat(pojo.getCron(), is(\"0/1 * * * * ?\"));\n        assertNull(pojo.getShardingItemParameters());\n        assertThat(pojo.getJobParameter(), is(\"param\"));\n        assertThat(pojo.isMonitorExecution(), is(true));\n        assertThat(pojo.getMaxTimeDiffSeconds(), is(-1));\n        assertFalse(pojo.isFailover());\n        assertTrue(pojo.isMisfire());\n        assertNull(pojo.getJobShardingStrategyType());\n        assertThat(pojo.getReconcileIntervalMinutes(), is(10));\n        assertThat(pojo.getDescription(), is(\"\"));\n    }\n    \n    @Test\n    void assertUpdateJobConfig() {\n        JobConfigurationPOJO jobConfig = new JobConfigurationPOJO();\n        jobConfig.setJobName(\"test_job\");\n        jobConfig.setCron(\"0/1 * * * * ?\");\n        jobConfig.setShardingTotalCount(3);\n        jobConfig.setJobParameter(\"param\");\n        jobConfig.setMonitorExecution(true);\n        jobConfig.setFailover(false);\n        jobConfig.setMisfire(true);\n        jobConfig.setMaxTimeDiffSeconds(-1);\n        jobConfig.setReconcileIntervalMinutes(10);\n        jobConfig.setDescription(\"\");\n        jobConfig.getProps().setProperty(DataflowJobProperties.STREAM_PROCESS_KEY, \"true\");\n        jobConfigAPI.updateJobConfiguration(jobConfig);\n        verify(regCenter).update(\"/test_job/config\", LifecycleYamlConstants.getDataflowJobYaml());\n    }\n    \n    @Test\n    void assertUpdateJobConfigIfJobNameIsEmpty() {\n        assertThrows(IllegalArgumentException.class, () -> {\n            JobConfigurationPOJO jobConfig = new JobConfigurationPOJO();\n            jobConfig.setJobName(\"\");\n            jobConfigAPI.updateJobConfiguration(jobConfig);\n        });\n    }\n    \n    @Test\n    void assertUpdateJobConfigIfCronIsEmpty() {\n        assertThrows(IllegalArgumentException.class, () -> {\n            JobConfigurationPOJO jobConfig = new JobConfigurationPOJO();\n            jobConfig.setJobName(\"test_job\");\n            jobConfig.setCron(\"\");\n            jobConfigAPI.updateJobConfiguration(jobConfig);\n        });\n    }\n    \n    @Test\n    void assertUpdateJobConfigIfShardingTotalCountLessThanOne() {\n        assertThrows(IllegalArgumentException.class, () -> {\n            JobConfigurationPOJO jobConfig = new JobConfigurationPOJO();\n            jobConfig.setJobName(\"test_job\");\n            jobConfig.setCron(\"0/1 * * * * ?\");\n            jobConfig.setShardingTotalCount(0);\n            jobConfigAPI.updateJobConfiguration(jobConfig);\n        });\n    }\n    \n    @Test\n    void assertRemoveJobConfiguration() {\n        jobConfigAPI.removeJobConfiguration(\"test_job\");\n        verify(regCenter).remove(\"/test_job\");\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/test/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/statistics/JobStatisticsAPIImplTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.statistics;\n\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.JobStatisticsAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.JobBriefInfo;\nimport org.apache.shardingsphere.elasticjob.lifecycle.fixture.LifecycleYamlConstants;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass JobStatisticsAPIImplTest {\n    \n    private JobStatisticsAPI jobStatisticsAPI;\n    \n    // TODO We should not use `Mock.Strictness.LENIENT` here, but the default. This is a flaw in the unit test design.\n    @Mock(strictness = Mock.Strictness.LENIENT)\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeEach\n    void setUp() {\n        jobStatisticsAPI = new JobStatisticsAPIImpl(regCenter);\n    }\n    \n    @Test\n    void assertGetJobsTotalCount() {\n        when(regCenter.getChildrenKeys(\"/\")).thenReturn(Arrays.asList(\"test_job_1\", \"test_job_2\"));\n        assertThat(jobStatisticsAPI.getJobsTotalCount(), is(2));\n    }\n    \n    @Test\n    void assertGetOKJobBriefInfo() {\n        when(regCenter.get(\"/test_job/config\")).thenReturn(LifecycleYamlConstants.getSimpleJobYaml(\"test_job\", \"desc\"));\n        when(regCenter.getChildrenKeys(\"/test_job/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        when(regCenter.getChildrenKeys(\"/test_job/instances\")).thenReturn(Arrays.asList(\"ip1@-@defaultInstance\", \"ip2@-@defaultInstance\"));\n        when(regCenter.getChildrenKeys(\"/test_job/sharding\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        when(regCenter.get(\"/test_job/sharding/0/instance\")).thenReturn(\"ip1@-@defaultInstance\");\n        when(regCenter.get(\"/test_job/sharding/1/instance\")).thenReturn(\"ip1@-@defaultInstance\");\n        when(regCenter.get(\"/test_job/sharding/2/instance\")).thenReturn(\"ip2@-@defaultInstance\");\n        when(regCenter.getChildrenKeys(\"/test_job/instances\")).thenReturn(Arrays.asList(\"ip1@-@defaultInstance\", \"ip2@-@defaultInstance\"));\n        JobBriefInfo jobBrief = jobStatisticsAPI.getJobBriefInfo(\"test_job\");\n        assertThat(jobBrief.getJobName(), is(\"test_job\"));\n        assertThat(jobBrief.getDescription(), is(\"desc\"));\n        assertThat(jobBrief.getCron(), is(\"0/1 * * * * ?\"));\n        assertThat(jobBrief.getInstanceCount(), is(2));\n        assertThat(jobBrief.getShardingTotalCount(), is(3));\n        assertThat(jobBrief.getStatus(), is(JobBriefInfo.JobStatus.OK));\n    }\n    \n    @Test\n    void assertGetOKJobBriefInfoWithPartialDisabledServer() {\n        when(regCenter.get(\"/test_job/config\")).thenReturn(LifecycleYamlConstants.getSimpleJobYaml(\"test_job\", \"desc\"));\n        when(regCenter.getChildrenKeys(\"/test_job/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        when(regCenter.get(\"/test_job/servers/ip1\")).thenReturn(\"DISABLED\");\n        when(regCenter.getChildrenKeys(\"/test_job/instances\")).thenReturn(Arrays.asList(\"ip1@-@defaultInstance\", \"ip2@-@defaultInstance\"));\n        when(regCenter.getChildrenKeys(\"/test_job/sharding\")).thenReturn(Arrays.asList(\"0\", \"1\"));\n        when(regCenter.get(\"/test_job/sharding/0/instance\")).thenReturn(\"ip1@-@defaultInstance\");\n        when(regCenter.get(\"/test_job/sharding/1/instance\")).thenReturn(\"ip2@-@defaultInstance\");\n        JobBriefInfo jobBrief = jobStatisticsAPI.getJobBriefInfo(\"test_job\");\n        assertThat(jobBrief.getStatus(), is(JobBriefInfo.JobStatus.OK));\n    }\n    \n    @Test\n    void assertGetDisabledJobBriefInfo() {\n        when(regCenter.get(\"/test_job/config\")).thenReturn(LifecycleYamlConstants.getSimpleJobYaml(\"test_job\", \"desc\"));\n        when(regCenter.getChildrenKeys(\"/test_job/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        when(regCenter.get(\"/test_job/servers/ip1\")).thenReturn(\"DISABLED\");\n        when(regCenter.get(\"/test_job/servers/ip2\")).thenReturn(\"DISABLED\");\n        when(regCenter.getChildrenKeys(\"/test_job/instances\")).thenReturn(Arrays.asList(\"ip1@-@defaultInstance\", \"ip2@-@defaultInstance\"));\n        JobBriefInfo jobBrief = jobStatisticsAPI.getJobBriefInfo(\"test_job\");\n        assertThat(jobBrief.getStatus(), is(JobBriefInfo.JobStatus.DISABLED));\n    }\n    \n    @Test\n    void assertGetShardingErrorJobBriefInfo() {\n        when(regCenter.get(\"/test_job/config\")).thenReturn(LifecycleYamlConstants.getSimpleJobYaml(\"test_job\", \"desc\"));\n        when(regCenter.getChildrenKeys(\"/test_job/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        when(regCenter.getChildrenKeys(\"/test_job/instances\")).thenReturn(Arrays.asList(\"ip1@-@defaultInstance\", \"ip2@-@defaultInstance\"));\n        when(regCenter.getChildrenKeys(\"/test_job/sharding\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\"));\n        when(regCenter.get(\"/test_job/sharding/0/instance\")).thenReturn(\"ip1@-@defaultInstance\");\n        when(regCenter.get(\"/test_job/sharding/1/instance\")).thenReturn(\"ip2@-@defaultInstance\");\n        when(regCenter.get(\"/test_job/sharding/2/instance\")).thenReturn(\"ip3@-@defaultInstance\");\n        JobBriefInfo jobBrief = jobStatisticsAPI.getJobBriefInfo(\"test_job\");\n        assertThat(jobBrief.getStatus(), is(JobBriefInfo.JobStatus.SHARDING_FLAG));\n    }\n    \n    @Test\n    void assertGetCrashedJobBriefInfo() {\n        when(regCenter.get(\"/test_job/config\")).thenReturn(LifecycleYamlConstants.getSimpleJobYaml(\"test_job\", \"desc\"));\n        JobBriefInfo jobBrief = jobStatisticsAPI.getJobBriefInfo(\"test_job\");\n        assertThat(jobBrief.getStatus(), is(JobBriefInfo.JobStatus.CRASHED));\n    }\n    \n    @Test\n    void assertGetAllJobsBriefInfoWithoutNamespace() {\n        when(regCenter.getChildrenKeys(\"/\")).thenReturn(Arrays.asList(\"test_job_1\", \"test_job_2\"));\n        assertThat(jobStatisticsAPI.getAllJobsBriefInfo().size(), is(0));\n    }\n    \n    @Test\n    void assertGetAllJobsBriefInfo() {\n        when(regCenter.getChildrenKeys(\"/\")).thenReturn(Arrays.asList(\"test_job_1\", \"test_job_2\"));\n        when(regCenter.get(\"/test_job_1/config\")).thenReturn(LifecycleYamlConstants.getSimpleJobYaml(\"test_job_1\", \"desc1\"));\n        when(regCenter.get(\"/test_job_2/config\")).thenReturn(LifecycleYamlConstants.getSimpleJobYaml(\"test_job_2\", \"desc2\"));\n        when(regCenter.getChildrenKeys(\"/test_job_1/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        when(regCenter.getChildrenKeys(\"/test_job_2/servers\")).thenReturn(Arrays.asList(\"ip3\", \"ip4\"));\n        when(regCenter.getChildrenKeys(\"/test_job_1/sharding\")).thenReturn(Arrays.asList(\"0\", \"1\"));\n        when(regCenter.get(\"/test_job_1/sharding/0/instance\")).thenReturn(\"ip1@-@defaultInstance\");\n        when(regCenter.get(\"/test_job_1/sharding/1/instance\")).thenReturn(\"ip2@-@defaultInstance\");\n        when(regCenter.getChildrenKeys(\"/test_job_2/sharding\")).thenReturn(Arrays.asList(\"0\", \"1\"));\n        when(regCenter.get(\"/test_job_2/sharding/0/instance\")).thenReturn(\"ip3@-@defaultInstance\");\n        when(regCenter.get(\"/test_job_2/sharding/1/instance\")).thenReturn(\"ip4@-@defaultInstance\");\n        when(regCenter.getChildrenKeys(\"/test_job_1/instances\")).thenReturn(Arrays.asList(\"ip1@-@defaultInstance\", \"ip2@-@defaultInstance\"));\n        when(regCenter.getChildrenKeys(\"/test_job_2/instances\")).thenReturn(Arrays.asList(\"ip3@-@defaultInstance\", \"ip4@-@defaultInstance\"));\n        int i = 0;\n        for (JobBriefInfo each : jobStatisticsAPI.getAllJobsBriefInfo()) {\n            i++;\n            assertThat(each.getJobName(), is(\"test_job_\" + i));\n            assertThat(each.getDescription(), is(\"desc\" + i));\n            assertThat(each.getCron(), is(\"0/1 * * * * ?\"));\n            assertThat(each.getInstanceCount(), is(2));\n            assertThat(each.getShardingTotalCount(), is(3));\n            assertThat(each.getStatus(), is(JobBriefInfo.JobStatus.OK));\n        }\n    }\n    \n    @Test\n    void assertGetJobsBriefInfoByIp() {\n        when(regCenter.getChildrenKeys(\"/\")).thenReturn(Arrays.asList(\"test_job_1\", \"test_job_2\", \"test_job_3\"));\n        when(regCenter.isExisted(\"/test_job_1/servers/ip1\")).thenReturn(true);\n        when(regCenter.isExisted(\"/test_job_2/servers/ip1\")).thenReturn(true);\n        when(regCenter.get(\"/test_job_2/servers/ip1\")).thenReturn(\"DISABLED\");\n        when(regCenter.getChildrenKeys(\"/test_job_1/instances\")).thenReturn(Collections.singletonList(\"ip1@-@defaultInstance\"));\n        when(regCenter.get(\"/test_job_1/instances/ip1@-@defaultInstance\")).thenReturn(\"jobInstanceId: ip1@-@defaultInstance\\nserverIp: ip1\\n\");\n        int i = 0;\n        for (JobBriefInfo each : jobStatisticsAPI.getJobsBriefInfo(\"ip1\")) {\n            assertThat(each.getJobName(), is(\"test_job_\" + ++i));\n            if (i == 1) {\n                assertThat(each.getInstanceCount(), is(1));\n                assertThat(each.getStatus(), is(JobBriefInfo.JobStatus.OK));\n            } else if (i == 2) {\n                assertThat(each.getInstanceCount(), is(0));\n                assertThat(each.getStatus(), is(JobBriefInfo.JobStatus.DISABLED));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/test/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/statistics/ServerStatisticsAPIImplTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.statistics;\n\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.ServerStatisticsAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.ServerBriefInfo;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.fail;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ServerStatisticsAPIImplTest {\n    \n    private ServerStatisticsAPI serverStatisticsAPI;\n    \n    @Mock\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeEach\n    void setUp() {\n        serverStatisticsAPI = new ServerStatisticsAPIImpl(regCenter);\n    }\n    \n    @Test\n    void assertGetJobsTotalCount() {\n        when(regCenter.getChildrenKeys(\"/\")).thenReturn(Arrays.asList(\"test_job_1\", \"test_job_2\"));\n        when(regCenter.getChildrenKeys(\"/test_job_1/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        when(regCenter.getChildrenKeys(\"/test_job_2/servers\")).thenReturn(Arrays.asList(\"ip2\", \"ip3\"));\n        assertThat(serverStatisticsAPI.getServersTotalCount(), is(3));\n    }\n    \n    @Test\n    void assertGetAllServersBriefInfo() {\n        when(regCenter.getChildrenKeys(\"/\")).thenReturn(Arrays.asList(\"test_job1\", \"test_job2\"));\n        when(regCenter.getChildrenKeys(\"/test_job1/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        when(regCenter.getChildrenKeys(\"/test_job2/servers\")).thenReturn(Arrays.asList(\"ip1\", \"ip2\"));\n        when(regCenter.get(\"/test_job1/servers/ip1\")).thenReturn(\"DISABLED\");\n        when(regCenter.get(\"/test_job1/servers/ip2\")).thenReturn(\"\");\n        when(regCenter.getChildrenKeys(\"/test_job1/instances\")).thenReturn(Collections.singletonList(\"ip1@-@defaultInstance\"));\n        \n        when(regCenter.get(\"/test_job2/servers/ip1\")).thenReturn(\"DISABLED\");\n        when(regCenter.get(\"/test_job2/servers/ip2\")).thenReturn(\"DISABLED\");\n        when(regCenter.get(\"/test_job1/instances/ip1@-@defaultInstance\")).thenReturn(\"jobInstanceId: ip1@-@defaultInstance\\nserverIp: ip1\\n\");\n        when(regCenter.get(\"/test_job2/instances/ip1@-@defaultInstance\")).thenReturn(\"jobInstanceId: ip1@-@defaultInstance\\nserverIp: ip1\\n\");\n        when(regCenter.get(\"/test_job2/instances/ip2@-@defaultInstance2\")).thenReturn(\"jobInstanceId: ip2@-@defaultInstance2\\nserverIp: ip2\\n\");\n        when(regCenter.getChildrenKeys(\"/test_job2/instances\")).thenReturn(Arrays.asList(\"ip1@-@defaultInstance\", \"ip2@-@defaultInstance2\"));\n        \n        int i = 0;\n        for (ServerBriefInfo each : serverStatisticsAPI.getAllServersBriefInfo()) {\n            i++;\n            assertThat(each.getServerIp(), is(\"ip\" + i));\n            switch (i) {\n                case 1:\n                    assertThat(each.getDisabledJobsNum().intValue(), is(2));\n                    assertThat(each.getJobsNum(), is(2));\n                    assertThat(each.getInstancesNum(), is(1));\n                    break;\n                case 2:\n                    assertThat(each.getDisabledJobsNum().intValue(), is(1));\n                    assertThat(each.getJobsNum(), is(2));\n                    assertThat(each.getInstancesNum(), is(1));\n                    break;\n                default:\n                    fail();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/test/java/org/apache/shardingsphere/elasticjob/lifecycle/internal/statistics/ShardingStatisticsAPIImplTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.lifecycle.internal.statistics;\n\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.ShardingStatisticsAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.ShardingInfo;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.Arrays;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ShardingStatisticsAPIImplTest {\n    \n    private ShardingStatisticsAPI shardingStatisticsAPI;\n    \n    // TODO We should not use `Mock.Strictness.LENIENT` here, but the default. This is a flaw in the unit test design.\n    @Mock(strictness = Mock.Strictness.LENIENT)\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeEach\n    void setUp() {\n        shardingStatisticsAPI = new ShardingStatisticsAPIImpl(regCenter);\n    }\n    \n    @Test\n    void assertGetShardingInfo() {\n        when(regCenter.getChildrenKeys(\"/test_job/sharding\")).thenReturn(Arrays.asList(\"0\", \"1\", \"2\", \"3\"));\n        when(regCenter.get(\"/test_job/sharding/0/instance\")).thenReturn(\"ip1@-@1234\");\n        when(regCenter.get(\"/test_job/sharding/1/instance\")).thenReturn(\"ip2@-@2341\");\n        when(regCenter.get(\"/test_job/sharding/2/instance\")).thenReturn(\"ip3@-@3412\");\n        when(regCenter.get(\"/test_job/sharding/3/instance\")).thenReturn(\"ip4@-@4123\");\n        when(regCenter.get(\"/test_job/instances/ip1@-@1234\")).thenReturn(\"jobInstanceId: ip1@-@1234\\nserverIp: ip1\\n\");\n        when(regCenter.get(\"/test_job/instances/ip2@-@2341\")).thenReturn(\"jobInstanceId: ip2@-@2341\\nserverIp: ip2\\n\");\n        when(regCenter.get(\"/test_job/instances/ip3@-@3412\")).thenReturn(\"jobInstanceId: ip3@-@3412\\nserverIp: ip3\\n\");\n        when(regCenter.get(\"/test_job/instances/ip4@-@4123\")).thenReturn(\"jobInstanceId: ip4@-@4123\\nserverIp: ip4\\n\");\n        when(regCenter.isExisted(\"/test_job/instances/ip4@-@4123\")).thenReturn(true);\n        when(regCenter.isExisted(\"/test_job/sharding/0/running\")).thenReturn(true);\n        when(regCenter.isExisted(\"/test_job/sharding/1/running\")).thenReturn(false);\n        when(regCenter.isExisted(\"/test_job/sharding/2/running\")).thenReturn(false);\n        when(regCenter.isExisted(\"/test_job/sharding/3/running\")).thenReturn(false);\n        when(regCenter.isExisted(\"/test_job/sharding/0/failover\")).thenReturn(false);\n        when(regCenter.isExisted(\"/test_job/sharding/1/failover\")).thenReturn(true);\n        when(regCenter.isExisted(\"/test_job/sharding/2/disabled\")).thenReturn(true);\n        int i = 0;\n        for (ShardingInfo each : shardingStatisticsAPI.getShardingInfo(\"test_job\")) {\n            i++;\n            assertThat(each.getItem(), is(i - 1));\n            switch (i) {\n                case 1:\n                    assertThat(each.getStatus(), is(ShardingInfo.ShardingStatus.RUNNING));\n                    assertThat(each.getServerIp(), is(\"ip1\"));\n                    assertThat(each.getInstanceId(), is(\"ip1@-@1234\"));\n                    break;\n                case 2:\n                    assertTrue(each.isFailover());\n                    assertThat(each.getStatus(), is(ShardingInfo.ShardingStatus.SHARDING_FLAG));\n                    assertThat(each.getServerIp(), is(\"ip2\"));\n                    assertThat(each.getInstanceId(), is(\"ip2@-@2341\"));\n                    break;\n                case 3:\n                    assertThat(each.getStatus(), is(ShardingInfo.ShardingStatus.DISABLED));\n                    assertThat(each.getServerIp(), is(\"ip3\"));\n                    assertThat(each.getInstanceId(), is(\"ip3@-@3412\"));\n                    break;\n                case 4:\n                    assertThat(each.getStatus(), is(ShardingInfo.ShardingStatus.PENDING));\n                    assertThat(each.getServerIp(), is(\"ip4\"));\n                    assertThat(each.getInstanceId(), is(\"ip4@-@4123\"));\n                    break;\n                default:\n                    break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "lifecycle/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n            <level>ERROR</level>\n        </filter>\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n</configuration>\n"
  },
  {
    "path": "lombok.config",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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# this config is to ignore lombok code in jacoco\nlombok.addLombokGeneratedAnnotation = true\n"
  },
  {
    "path": "mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  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,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Apache Maven Wrapper startup batch script, version 3.3.4\n#\n# Optional ENV vars\n# -----------------\n#   JAVA_HOME - location of a JDK home dir, required when download maven via java source\n#   MVNW_REPOURL - repo url base for downloading maven distribution\n#   MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven\n#   MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output\n# ----------------------------------------------------------------------------\n\nset -euf\n[ \"${MVNW_VERBOSE-}\" != debug ] || set -x\n\n# OS specific support.\nnative_path() { printf %s\\\\n \"$1\"; }\ncase \"$(uname)\" in\nCYGWIN* | MINGW*)\n  [ -z \"${JAVA_HOME-}\" ] || JAVA_HOME=\"$(cygpath --unix \"$JAVA_HOME\")\"\n  native_path() { cygpath --path --windows \"$1\"; }\n  ;;\nesac\n\n# set JAVACMD and JAVACCMD\nset_java_home() {\n  # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched\n  if [ -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      JAVACCMD=\"$JAVA_HOME/jre/sh/javac\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n      JAVACCMD=\"$JAVA_HOME/bin/javac\"\n\n      if [ ! -x \"$JAVACMD\" ] || [ ! -x \"$JAVACCMD\" ]; then\n        echo \"The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run.\" >&2\n        echo \"JAVA_HOME is set to \\\"$JAVA_HOME\\\", but \\\"\\$JAVA_HOME/bin/java\\\" or \\\"\\$JAVA_HOME/bin/javac\\\" does not exist.\" >&2\n        return 1\n      fi\n    fi\n  else\n    JAVACMD=\"$(\n      'set' +e\n      'unset' -f command 2>/dev/null\n      'command' -v java\n    )\" || :\n    JAVACCMD=\"$(\n      'set' +e\n      'unset' -f command 2>/dev/null\n      'command' -v javac\n    )\" || :\n\n    if [ ! -x \"${JAVACMD-}\" ] || [ ! -x \"${JAVACCMD-}\" ]; then\n      echo \"The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run.\" >&2\n      return 1\n    fi\n  fi\n}\n\n# hash string like Java String::hashCode\nhash_string() {\n  str=\"${1:-}\" h=0\n  while [ -n \"$str\" ]; do\n    char=\"${str%\"${str#?}\"}\"\n    h=$(((h * 31 + $(LC_CTYPE=C printf %d \"'$char\")) % 4294967296))\n    str=\"${str#?}\"\n  done\n  printf %x\\\\n $h\n}\n\nverbose() { :; }\n[ \"${MVNW_VERBOSE-}\" != true ] || verbose() { printf %s\\\\n \"${1-}\"; }\n\ndie() {\n  printf %s\\\\n \"$1\" >&2\n  exit 1\n}\n\ntrim() {\n  # MWRAPPER-139:\n  #   Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.\n  #   Needed for removing poorly interpreted newline sequences when running in more\n  #   exotic environments such as mingw bash on Windows.\n  printf \"%s\" \"${1}\" | tr -d '[:space:]'\n}\n\nscriptDir=\"$(dirname \"$0\")\"\nscriptName=\"$(basename \"$0\")\"\n\n# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties\nwhile IFS=\"=\" read -r key value; do\n  case \"${key-}\" in\n  distributionUrl) distributionUrl=$(trim \"${value-}\") ;;\n  distributionSha256Sum) distributionSha256Sum=$(trim \"${value-}\") ;;\n  esac\ndone <\"$scriptDir/.mvn/wrapper/maven-wrapper.properties\"\n[ -n \"${distributionUrl-}\" ] || die \"cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties\"\n\ncase \"${distributionUrl##*/}\" in\nmaven-mvnd-*bin.*)\n  MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/\n  case \"${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)\" in\n  *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;\n  :Darwin*x86_64) distributionPlatform=darwin-amd64 ;;\n  :Darwin*arm64) distributionPlatform=darwin-aarch64 ;;\n  :Linux*x86_64*) distributionPlatform=linux-amd64 ;;\n  *)\n    echo \"Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version\" >&2\n    distributionPlatform=linux-amd64\n    ;;\n  esac\n  distributionUrl=\"${distributionUrl%-bin.*}-$distributionPlatform.zip\"\n  ;;\nmaven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;\n*) MVN_CMD=\"mvn${scriptName#mvnw}\" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;\nesac\n\n# apply MVNW_REPOURL and calculate MAVEN_HOME\n# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>\n[ -z \"${MVNW_REPOURL-}\" ] || distributionUrl=\"$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*\"$_MVNW_REPO_PATTERN\"}\"\ndistributionUrlName=\"${distributionUrl##*/}\"\ndistributionUrlNameMain=\"${distributionUrlName%.*}\"\ndistributionUrlNameMain=\"${distributionUrlNameMain%-bin}\"\nMAVEN_USER_HOME=\"${MAVEN_USER_HOME:-${HOME}/.m2}\"\nMAVEN_HOME=\"${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string \"$distributionUrl\")\"\n\nexec_maven() {\n  unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :\n  exec \"$MAVEN_HOME/bin/$MVN_CMD\" \"$@\" || die \"cannot exec $MAVEN_HOME/bin/$MVN_CMD\"\n}\n\nif [ -d \"$MAVEN_HOME\" ]; then\n  verbose \"found existing MAVEN_HOME at $MAVEN_HOME\"\n  exec_maven \"$@\"\nfi\n\ncase \"${distributionUrl-}\" in\n*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;\n*) die \"distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'\" ;;\nesac\n\n# prepare tmp dir\nif TMP_DOWNLOAD_DIR=\"$(mktemp -d)\" && [ -d \"$TMP_DOWNLOAD_DIR\" ]; then\n  clean() { rm -rf -- \"$TMP_DOWNLOAD_DIR\"; }\n  trap clean HUP INT TERM EXIT\nelse\n  die \"cannot create temp dir\"\nfi\n\nmkdir -p -- \"${MAVEN_HOME%/*}\"\n\n# Download and Install Apache Maven\nverbose \"Couldn't find MAVEN_HOME, downloading and installing it ...\"\nverbose \"Downloading from: $distributionUrl\"\nverbose \"Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName\"\n\n# select .zip or .tar.gz\nif ! command -v unzip >/dev/null; then\n  distributionUrl=\"${distributionUrl%.zip}.tar.gz\"\n  distributionUrlName=\"${distributionUrl##*/}\"\nfi\n\n# verbose opt\n__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''\n[ \"${MVNW_VERBOSE-}\" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v\n\n# normalize http auth\ncase \"${MVNW_PASSWORD:+has-password}\" in\n'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;\nhas-password) [ -n \"${MVNW_USERNAME-}\" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;\nesac\n\nif [ -z \"${MVNW_USERNAME-}\" ] && command -v wget >/dev/null; then\n  verbose \"Found wget ... using wget\"\n  wget ${__MVNW_QUIET_WGET:+\"$__MVNW_QUIET_WGET\"} \"$distributionUrl\" -O \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" || die \"wget: Failed to fetch $distributionUrl\"\nelif [ -z \"${MVNW_USERNAME-}\" ] && command -v curl >/dev/null; then\n  verbose \"Found curl ... using curl\"\n  curl ${__MVNW_QUIET_CURL:+\"$__MVNW_QUIET_CURL\"} -f -L -o \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" \"$distributionUrl\" || die \"curl: Failed to fetch $distributionUrl\"\nelif set_java_home; then\n  verbose \"Falling back to use Java to download\"\n  javaSource=\"$TMP_DOWNLOAD_DIR/Downloader.java\"\n  targetZip=\"$TMP_DOWNLOAD_DIR/$distributionUrlName\"\n  cat >\"$javaSource\" <<-END\n\tpublic class Downloader extends java.net.Authenticator\n\t{\n\t  protected java.net.PasswordAuthentication getPasswordAuthentication()\n\t  {\n\t    return new java.net.PasswordAuthentication( System.getenv( \"MVNW_USERNAME\" ), System.getenv( \"MVNW_PASSWORD\" ).toCharArray() );\n\t  }\n\t  public static void main( String[] args ) throws Exception\n\t  {\n\t    setDefault( new Downloader() );\n\t    java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );\n\t  }\n\t}\n\tEND\n  # For Cygwin/MinGW, switch paths to Windows format before running javac and java\n  verbose \" - Compiling Downloader.java ...\"\n  \"$(native_path \"$JAVACCMD\")\" \"$(native_path \"$javaSource\")\" || die \"Failed to compile Downloader.java\"\n  verbose \" - Running Downloader.java ...\"\n  \"$(native_path \"$JAVACMD\")\" -cp \"$(native_path \"$TMP_DOWNLOAD_DIR\")\" Downloader \"$distributionUrl\" \"$(native_path \"$targetZip\")\"\nfi\n\n# If specified, validate the SHA-256 sum of the Maven distribution zip file\nif [ -n \"${distributionSha256Sum-}\" ]; then\n  distributionSha256Result=false\n  if [ \"$MVN_CMD\" = mvnd.sh ]; then\n    echo \"Checksum validation is not supported for maven-mvnd.\" >&2\n    echo \"Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties.\" >&2\n    exit 1\n  elif command -v sha256sum >/dev/null; then\n    if echo \"$distributionSha256Sum  $TMP_DOWNLOAD_DIR/$distributionUrlName\" | sha256sum -c - >/dev/null 2>&1; then\n      distributionSha256Result=true\n    fi\n  elif command -v shasum >/dev/null; then\n    if echo \"$distributionSha256Sum  $TMP_DOWNLOAD_DIR/$distributionUrlName\" | shasum -a 256 -c >/dev/null 2>&1; then\n      distributionSha256Result=true\n    fi\n  else\n    echo \"Checksum validation was requested but neither 'sha256sum' or 'shasum' are available.\" >&2\n    echo \"Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties.\" >&2\n    exit 1\n  fi\n  if [ $distributionSha256Result = false ]; then\n    echo \"Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised.\" >&2\n    echo \"If you updated your Maven version, you need to update the specified distributionSha256Sum property.\" >&2\n    exit 1\n  fi\nfi\n\n# unzip and move\nif command -v unzip >/dev/null; then\n  unzip ${__MVNW_QUIET_UNZIP:+\"$__MVNW_QUIET_UNZIP\"} \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -d \"$TMP_DOWNLOAD_DIR\" || die \"failed to unzip\"\nelse\n  tar xzf${__MVNW_QUIET_TAR:+\"$__MVNW_QUIET_TAR\"} \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -C \"$TMP_DOWNLOAD_DIR\" || die \"failed to untar\"\nfi\n\n# Find the actual extracted directory name (handles snapshots where filename != directory name)\nactualDistributionDir=\"\"\n\n# First try the expected directory name (for regular distributions)\nif [ -d \"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain\" ]; then\n  if [ -f \"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD\" ]; then\n    actualDistributionDir=\"$distributionUrlNameMain\"\n  fi\nfi\n\n# If not found, search for any directory with the Maven executable (for snapshots)\nif [ -z \"$actualDistributionDir\" ]; then\n  # enable globbing to iterate over items\n  set +f\n  for dir in \"$TMP_DOWNLOAD_DIR\"/*; do\n    if [ -d \"$dir\" ]; then\n      if [ -f \"$dir/bin/$MVN_CMD\" ]; then\n        actualDistributionDir=\"$(basename \"$dir\")\"\n        break\n      fi\n    fi\n  done\n  set -f\nfi\n\nif [ -z \"$actualDistributionDir\" ]; then\n  verbose \"Contents of $TMP_DOWNLOAD_DIR:\"\n  verbose \"$(ls -la \"$TMP_DOWNLOAD_DIR\")\"\n  die \"Could not find Maven distribution directory in extracted archive\"\nfi\n\nverbose \"Found extracted Maven distribution directory: $actualDistributionDir\"\nprintf %s\\\\n \"$distributionUrl\" >\"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url\"\nmv -- \"$TMP_DOWNLOAD_DIR/$actualDistributionDir\" \"$MAVEN_HOME\" || [ -d \"$MAVEN_HOME\" ] || die \"fail to move MAVEN_HOME\"\n\nclean || :\nexec_maven \"$@\"\n"
  },
  {
    "path": "mvnw.cmd",
    "content": "<# : batch portion\n@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    http://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Apache Maven Wrapper startup batch script, version 3.3.4\n@REM\n@REM Optional ENV vars\n@REM   MVNW_REPOURL - repo url base for downloading maven distribution\n@REM   MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven\n@REM   MVNW_VERBOSE - true: enable verbose log; others: silence the output\n@REM ----------------------------------------------------------------------------\n\n@IF \"%__MVNW_ARG0_NAME__%\"==\"\" (SET __MVNW_ARG0_NAME__=%~nx0)\n@SET __MVNW_CMD__=\n@SET __MVNW_ERROR__=\n@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%\n@SET PSModulePath=\n@FOR /F \"usebackq tokens=1* delims==\" %%A IN (`powershell -noprofile \"& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}\"`) DO @(\n  IF \"%%A\"==\"MVN_CMD\" (set __MVNW_CMD__=%%B) ELSE IF \"%%B\"==\"\" (echo %%A) ELSE (echo %%A=%%B)\n)\n@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%\n@SET __MVNW_PSMODULEP_SAVE=\n@SET __MVNW_ARG0_NAME__=\n@SET MVNW_USERNAME=\n@SET MVNW_PASSWORD=\n@IF NOT \"%__MVNW_CMD__%\"==\"\" (\"%__MVNW_CMD__%\" %*)\n@echo Cannot start maven from wrapper >&2 && exit /b 1\n@GOTO :EOF\n: end batch / begin powershell #>\n\n$ErrorActionPreference = \"Stop\"\nif ($env:MVNW_VERBOSE -eq \"true\") {\n  $VerbosePreference = \"Continue\"\n}\n\n# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties\n$distributionUrl = (Get-Content -Raw \"$scriptDir/.mvn/wrapper/maven-wrapper.properties\" | ConvertFrom-StringData).distributionUrl\nif (!$distributionUrl) {\n  Write-Error \"cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties\"\n}\n\nswitch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {\n  \"maven-mvnd-*\" {\n    $USE_MVND = $true\n    $distributionUrl = $distributionUrl -replace '-bin\\.[^.]*$',\"-windows-amd64.zip\"\n    $MVN_CMD = \"mvnd.cmd\"\n    break\n  }\n  default {\n    $USE_MVND = $false\n    $MVN_CMD = $script -replace '^mvnw','mvn'\n    break\n  }\n}\n\n# apply MVNW_REPOURL and calculate MAVEN_HOME\n# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>\nif ($env:MVNW_REPOURL) {\n  $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { \"/org/apache/maven/\" } else { \"/maven/mvnd/\" }\n  $distributionUrl = \"$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace \"^.*$MVNW_REPO_PATTERN\",'')\"\n}\n$distributionUrlName = $distributionUrl -replace '^.*/',''\n$distributionUrlNameMain = $distributionUrlName -replace '\\.[^.]*$','' -replace '-bin$',''\n\n$MAVEN_M2_PATH = \"$HOME/.m2\"\nif ($env:MAVEN_USER_HOME) {\n  $MAVEN_M2_PATH = \"$env:MAVEN_USER_HOME\"\n}\n\nif (-not (Test-Path -Path $MAVEN_M2_PATH)) {\n    New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null\n}\n\n$MAVEN_WRAPPER_DISTS = $null\nif ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) {\n  $MAVEN_WRAPPER_DISTS = \"$MAVEN_M2_PATH/wrapper/dists\"\n} else {\n  $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + \"/wrapper/dists\"\n}\n\n$MAVEN_HOME_PARENT = \"$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain\"\n$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString(\"x2\")}) -join ''\n$MAVEN_HOME = \"$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME\"\n\nif (Test-Path -Path \"$MAVEN_HOME\" -PathType Container) {\n  Write-Verbose \"found existing MAVEN_HOME at $MAVEN_HOME\"\n  Write-Output \"MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD\"\n  exit $?\n}\n\nif (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {\n  Write-Error \"distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl\"\n}\n\n# prepare tmp dir\n$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile\n$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path \"$TMP_DOWNLOAD_DIR_HOLDER.dir\"\n$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null\ntrap {\n  if ($TMP_DOWNLOAD_DIR.Exists) {\n    try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }\n    catch { Write-Warning \"Cannot remove $TMP_DOWNLOAD_DIR\" }\n  }\n}\n\nNew-Item -Itemtype Directory -Path \"$MAVEN_HOME_PARENT\" -Force | Out-Null\n\n# Download and Install Apache Maven\nWrite-Verbose \"Couldn't find MAVEN_HOME, downloading and installing it ...\"\nWrite-Verbose \"Downloading from: $distributionUrl\"\nWrite-Verbose \"Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName\"\n\n$webclient = New-Object System.Net.WebClient\nif ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {\n  $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)\n}\n[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n$webclient.DownloadFile($distributionUrl, \"$TMP_DOWNLOAD_DIR/$distributionUrlName\") | Out-Null\n\n# If specified, validate the SHA-256 sum of the Maven distribution zip file\n$distributionSha256Sum = (Get-Content -Raw \"$scriptDir/.mvn/wrapper/maven-wrapper.properties\" | ConvertFrom-StringData).distributionSha256Sum\nif ($distributionSha256Sum) {\n  if ($USE_MVND) {\n    Write-Error \"Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties.\"\n  }\n  Import-Module $PSHOME\\Modules\\Microsoft.PowerShell.Utility -Function Get-FileHash\n  if ((Get-FileHash \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {\n    Write-Error \"Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property.\"\n  }\n}\n\n# unzip and move\nExpand-Archive \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -DestinationPath \"$TMP_DOWNLOAD_DIR\" | Out-Null\n\n# Find the actual extracted directory name (handles snapshots where filename != directory name)\n$actualDistributionDir = \"\"\n\n# First try the expected directory name (for regular distributions)\n$expectedPath = Join-Path \"$TMP_DOWNLOAD_DIR\" \"$distributionUrlNameMain\"\n$expectedMvnPath = Join-Path \"$expectedPath\" \"bin/$MVN_CMD\"\nif ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) {\n  $actualDistributionDir = $distributionUrlNameMain\n}\n\n# If not found, search for any directory with the Maven executable (for snapshots)\nif (!$actualDistributionDir) {\n  Get-ChildItem -Path \"$TMP_DOWNLOAD_DIR\" -Directory | ForEach-Object {\n    $testPath = Join-Path $_.FullName \"bin/$MVN_CMD\"\n    if (Test-Path -Path $testPath -PathType Leaf) {\n      $actualDistributionDir = $_.Name\n    }\n  }\n}\n\nif (!$actualDistributionDir) {\n  Write-Error \"Could not find Maven distribution directory in extracted archive\"\n}\n\nWrite-Verbose \"Found extracted Maven distribution directory: $actualDistributionDir\"\nRename-Item -Path \"$TMP_DOWNLOAD_DIR/$actualDistributionDir\" -NewName $MAVEN_HOME_NAME | Out-Null\ntry {\n  Move-Item -Path \"$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME\" -Destination $MAVEN_HOME_PARENT | Out-Null\n} catch {\n  if (! (Test-Path -Path \"$MAVEN_HOME\" -PathType Container)) {\n    Write-Error \"fail to move MAVEN_HOME\"\n  }\n} finally {\n  try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }\n  catch { Write-Warning \"Cannot remove $TMP_DOWNLOAD_DIR\" }\n}\n\nWrite-Output \"MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD\"\n"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache</groupId>\n        <artifactId>apache</artifactId>\n        <version>21</version>\n    </parent>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob</artifactId>\n    <version>3.0.6-SNAPSHOT</version>\n    <packaging>pom</packaging>\n    <name>Elastic Job</name>\n    <description>Distributed scheduled job</description>\n    \n    <modules>\n        <module>api</module>\n        <module>registry-center</module>\n        <module>bootstrap</module>\n        <module>kernel</module>\n        <module>lifecycle</module>\n        <module>restful</module>\n        \n        <module>ecosystem</module>\n        <module>spring</module>\n        \n        <module>test</module>\n        \n        <module>distribution</module>\n        <module>reachability-metadata</module>\n    </modules>\n    \n    <properties>\n        <!-- Environments -->\n        <java.version>8</java.version>\n        <maven.compiler.source>${java.version}</maven.compiler.source>\n        <maven.compiler.target>${java.version}</maven.compiler.target>\n        <maven.compiler.release>${java.version}</maven.compiler.release>\n        <maven.version.range>[3.5.0,)</maven.version.range>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.deploy.skip>false</maven.deploy.skip>\n        \n        <!-- 3rd party library versions -->\n        <shardingsphere.version>5.4.1</shardingsphere.version>\n        \n        <guava.version>32.1.2-jre</guava.version>\n        <checker-qual.version>3.39.0</checker-qual.version>\n        <error_prone_annotations.version>2.22.0</error_prone_annotations.version>\n        <j2objc-annotations.version>1.3</j2objc-annotations.version>\n        \n        <commons-lang3.version>3.18.0</commons-lang3.version>\n        <snakeyaml.version>2.2</snakeyaml.version>\n        <gson.version>2.10.1</gson.version>\n        \n        <quartz.version>2.4.0</quartz.version>\n        \n        <zookeeper.version>3.9.5</zookeeper.version>\n        <curator.version>5.9.0</curator.version>\n        \n        <mail.version>1.6.0</mail.version>\n        <commons-codec.version>1.16.0</commons-codec.version>\n        <commons-exec.version>1.3</commons-exec.version>\n        <httpclient.version>4.5.14</httpclient.version>\n        <httpcore.version>4.4.16</httpcore.version>\n        \n        <netty.version>4.2.9.Final</netty.version>\n        \n        <slf4j.version>1.7.36</slf4j.version>\n        <logback.version>1.2.13</logback.version>\n        \n        <lombok.version>1.18.40</lombok.version>\n        \n        <junit.version>5.10.3</junit.version>\n        <hamcrest.version>3.0</hamcrest.version>\n        <mockito.version>4.11.0</mockito.version>\n        <awaitility.version>4.2.0</awaitility.version>\n        <bytebuddy.version>1.17.7</bytebuddy.version>\n        \n        <h2.version>2.2.224</h2.version>\n        <hikari-cp.version>4.0.3</hikari-cp.version>\n        \n        <spring-boot-dependencies.version>2.7.18</spring-boot-dependencies.version>\n        <spring-framework.version>5.3.39</spring-framework.version>\n        \n        <!-- Compile plugin versions -->\n        <maven-enforcer-plugin.version>3.2.1</maven-enforcer-plugin.version>\n        <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version>\n        <maven-resources-plugin.version>3.3.1</maven-resources-plugin.version>\n        <maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>\n        <maven-jar-plugin.version>3.3.0</maven-jar-plugin.version>\n        \n        <!-- Release plugin versions -->\n        <maven-source-plugin.version>3.2.1</maven-source-plugin.version>\n        <maven-deploy-plugin.version>3.1.1</maven-deploy-plugin.version>\n        <maven-release-plugin.version>3.0.0</maven-release-plugin.version>\n        <maven-assembly-plugin.version>3.5.0</maven-assembly-plugin.version>\n        \n        <!-- Check plugin versions -->\n        <apache-rat-plugin.version>0.15</apache-rat-plugin.version>\n        <spotless-maven-plugin.version>2.22.1</spotless-maven-plugin.version>\n        <maven-checkstyle-plugin.version>3.2.1</maven-checkstyle-plugin.version>\n        <findbugs-maven-plugin.version>3.0.2</findbugs-maven-plugin.version>\n        <maven-pmd-plugin.version>3.20.0</maven-pmd-plugin.version>\n        <coveralls-maven-plugin.version>4.3.0</coveralls-maven-plugin.version>\n        <cobertura-maven-plugin.version>2.7</cobertura-maven-plugin.version>\n        <jacoco-maven-plugin.version>0.8.13</jacoco-maven-plugin.version>\n        \n        <!-- Report plugin versions -->\n        <maven-site-plugin.version>4.0.0-M6</maven-site-plugin.version>\n        <maven-project-info-reports-plugin.version>3.4.2</maven-project-info-reports-plugin.version>\n        <maven-javadoc-plugin.version>3.5.0</maven-javadoc-plugin.version>\n        <maven-jxr-plugin.version>3.3.0</maven-jxr-plugin.version>\n        <jdepend-maven-plugin.version>2.0</jdepend-maven-plugin.version>\n        <taglist-maven-plugin.version>2.4</taglist-maven-plugin.version>\n        <maven-surefire-report-plugin.version>2.18.1</maven-surefire-report-plugin.version>\n        <lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>\n        <maven-plugin-plugin.version>3.4</maven-plugin-plugin.version>\n        <checksum-maven-plugin.version>1.10</checksum-maven-plugin.version>\n        \n        <native-maven-plugin.version>0.10.3</native-maven-plugin.version>\n    </properties>\n    \n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.apache.shardingsphere</groupId>\n                <artifactId>shardingsphere-infra-spi</artifactId>\n                <version>${shardingsphere.version}</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>com.google.guava</groupId>\n                <artifactId>guava</artifactId>\n                <version>${guava.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>com.google.guava</groupId>\n                        <artifactId>listenablefuture</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>org.checkerframework</groupId>\n                <artifactId>checker-qual</artifactId>\n                <version>${checker-qual.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.errorprone</groupId>\n                <artifactId>error_prone_annotations</artifactId>\n                <version>${error_prone_annotations.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.j2objc</groupId>\n                <artifactId>j2objc-annotations</artifactId>\n                <version>${j2objc-annotations.version}</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-lang3</artifactId>\n                <version>${commons-lang3.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.yaml</groupId>\n                <artifactId>snakeyaml</artifactId>\n                <version>${snakeyaml.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.code.gson</groupId>\n                <artifactId>gson</artifactId>\n                <version>${gson.version}</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.quartz-scheduler</groupId>\n                <artifactId>quartz</artifactId>\n                <version>${quartz.version}</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.apache.zookeeper</groupId>\n                <artifactId>zookeeper</artifactId>\n                <version>${zookeeper.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.curator</groupId>\n                <artifactId>curator-framework</artifactId>\n                <version>${curator.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.curator</groupId>\n                <artifactId>curator-client</artifactId>\n                <version>${curator.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.curator</groupId>\n                <artifactId>curator-recipes</artifactId>\n                <version>${curator.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.curator</groupId>\n                <artifactId>curator-test</artifactId>\n                <version>${curator.version}</version>\n                <scope>test</scope>\n            </dependency>\n            \n            <dependency>\n                <groupId>com.sun.mail</groupId>\n                <artifactId>javax.mail</artifactId>\n                <version>${mail.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-codec</groupId>\n                <artifactId>commons-codec</artifactId>\n                <version>${commons-codec.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-exec</artifactId>\n                <version>${commons-exec.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.httpcomponents</groupId>\n                <artifactId>httpclient</artifactId>\n                <version>${httpclient.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.httpcomponents</groupId>\n                <artifactId>httpcore</artifactId>\n                <version>${httpcore.version}</version>\n            </dependency>\n            \n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-bom</artifactId>\n                <version>${netty.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>slf4j-api</artifactId>\n                <version>${slf4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>jcl-over-slf4j</artifactId>\n                <version>${slf4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>jul-to-slf4j</artifactId>\n                <version>${slf4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>slf4j-jdk14</artifactId>\n                <version>${slf4j.version}</version>\n                <optional>true</optional>\n            </dependency>\n            <dependency>\n                <groupId>ch.qos.logback</groupId>\n                <artifactId>logback-core</artifactId>\n                <version>${logback.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>ch.qos.logback</groupId>\n                <artifactId>logback-classic</artifactId>\n                <version>${logback.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>org.slf4j</groupId>\n                        <artifactId>slf4j-api</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.projectlombok</groupId>\n                <artifactId>lombok</artifactId>\n                <version>${lombok.version}</version>\n                <scope>provided</scope>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.junit</groupId>\n                <artifactId>junit-bom</artifactId>\n                <version>${junit.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.hamcrest</groupId>\n                <artifactId>hamcrest</artifactId>\n                <version>${hamcrest.version}</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.mockito</groupId>\n                <artifactId>mockito-bom</artifactId>\n                <version>${mockito.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n                <exclusions>\n                    <exclusion>\n                        <groupId>net.bytebuddy</groupId>\n                        <artifactId>byte-buddy</artifactId>\n                    </exclusion>\n                    <exclusion>\n                        <groupId>net.bytebuddy</groupId>\n                        <artifactId>byte-buddy-agent</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>net.bytebuddy</groupId>\n                <artifactId>byte-buddy</artifactId>\n                <version>${bytebuddy.version}</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>net.bytebuddy</groupId>\n                <artifactId>byte-buddy-agent</artifactId>\n                <version>${bytebuddy.version}</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.awaitility</groupId>\n                <artifactId>awaitility</artifactId>\n                <version>${awaitility.version}</version>\n                <scope>test</scope>\n            </dependency>\n            \n            <dependency>\n                <groupId>com.h2database</groupId>\n                <artifactId>h2</artifactId>\n                <version>${h2.version}</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>com.zaxxer</groupId>\n                <artifactId>HikariCP</artifactId>\n                <version>${hikari-cp.version}</version>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n    \n    <dependencies>\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>jcl-over-slf4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>jul-to-slf4j</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.junit.jupiter</groupId>\n            <artifactId>junit-jupiter</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.hamcrest</groupId>\n            <artifactId>hamcrest</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-core</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-inline</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-junit-jupiter</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    \n    <build>\n        <finalName>apache-shardingsphere-elasticjob-${project.version}</finalName>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <artifactId>maven-compiler-plugin</artifactId>\n                    <version>${maven-compiler-plugin.version}</version>\n                    <configuration>\n                        <source>${java.version}</source>\n                        <target>${java.version}</target>\n                        <testSource>${java.version}</testSource>\n                        <testTarget>${java.version}</testTarget>\n                        <annotationProcessorPaths>\n                            <path>\n                                <groupId>org.projectlombok</groupId>\n                                <artifactId>lombok</artifactId>\n                                <version>${lombok.version}</version>\n                            </path>\n                        </annotationProcessorPaths>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-resources-plugin</artifactId>\n                    <version>${maven-resources-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-jar-plugin</artifactId>\n                    <version>${maven-jar-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-surefire-plugin</artifactId>\n                    <version>${maven-surefire-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-surefire-report-plugin</artifactId>\n                    <version>${maven-surefire-report-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-site-plugin</artifactId>\n                    <version>${maven-site-plugin.version}</version>\n                    <configuration>\n                        <locales>${project.build.locale}</locales>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>${lifecycle-mapping.version}</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <artifactId>maven-enforcer-plugin</artifactId>\n                                        <versionRange>[1.0.0,)</versionRange>\n                                        <goals>\n                                            <goal>enforce</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore />\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <artifactId>maven-plugin-plugin</artifactId>\n                                        <versionRange>[1.0.0,)</versionRange>\n                                        <goals>\n                                            <goal>descriptor</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore />\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-plugin-plugin</artifactId>\n                    <version>${maven-plugin-plugin.version}</version>\n                    <configuration>\n                        <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <id>default-descriptor</id>\n                            <phase>process-classes</phase>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-javadoc-plugin</artifactId>\n                    <version>${maven-javadoc-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-source-plugin</artifactId>\n                    <version>${maven-source-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-deploy-plugin</artifactId>\n                    <version>${maven-deploy-plugin.version}</version>\n                    <configuration>\n                        <skip>${maven.deploy.skip}</skip>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>net.nicoulaj.maven.plugins</groupId>\n                    <artifactId>checksum-maven-plugin</artifactId>\n                    <version>${checksum-maven-plugin.version}</version>\n                    <configuration>\n                        <appendFilename>true</appendFilename>\n                        <algorithms>\n                            <algorithm>SHA-512</algorithm>\n                        </algorithms>\n                        <fileSets>\n                            <fileSet>\n                                <includes>\n                                    <include>*.tar.gz</include>\n                                    <include>*.zip</include>\n                                </includes>\n                            </fileSet>\n                        </fileSets>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>artifacts</goal>\n                            </goals>\n                            <phase>package</phase>\n                        </execution>\n                    </executions>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n        <plugins>\n            <plugin>\n                <artifactId>maven-source-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>attach-sources</id>\n                        <goals>\n                            <goal>jar-no-fork</goal>\n                        </goals>\n                        <phase>verify</phase>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <artifactId>maven-javadoc-plugin</artifactId>\n                <configuration>\n                    <source>${java.version}</source>\n                    <charset>${project.build.sourceEncoding}</charset>\n                    <encoding>${project.build.sourceEncoding}</encoding>\n                    <docencoding>${project.build.sourceEncoding}</docencoding>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>attach-javadocs</id>\n                        <goals>\n                            <goal>jar</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <artifactId>maven-enforcer-plugin</artifactId>\n                <version>${maven-enforcer-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>enforce-banned-dependencies</id>\n                        <goals>\n                            <goal>enforce</goal>\n                        </goals>\n                        <configuration>\n                            <rules>\n                                <requireMavenVersion>\n                                    <version>${maven.version.range}</version>\n                                </requireMavenVersion>\n                                <requireJavaVersion>\n                                    <version>${java.version}</version>\n                                </requireJavaVersion>\n                            </rules>\n                            <fail>true</fail>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eluder.coveralls</groupId>\n                <artifactId>coveralls-maven-plugin</artifactId>\n                <version>${coveralls-maven-plugin.version}</version>\n            </plugin>\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>cobertura-maven-plugin</artifactId>\n                <version>${cobertura-maven-plugin.version}</version>\n                <configuration>\n                    <check>\n                        <branchRate>80</branchRate>\n                        <lineRate>80</lineRate>\n                        <haltOnFailure>true</haltOnFailure>\n                        <totalBranchRate>80</totalBranchRate>\n                        <totalLineRate>80</totalLineRate>\n                        <packageLineRate>80</packageLineRate>\n                        <packageBranchRate>80</packageBranchRate>\n                    </check>\n                    <aggregate>true</aggregate>\n                    <encoding>${project.build.sourceEncoding}</encoding>\n                    <quiet>true</quiet>\n                    <format>xml</format>\n                    <instrumentation>\n                        <ignoreTrivial>true</ignoreTrivial>\n                        <ignoreMethodAnnotations>\n                            <ignoreMethodAnnotation>lombok.Generated</ignoreMethodAnnotation>\n                        </ignoreMethodAnnotations>\n                        <excludes>\n                            <exclude>org/apache/**/*Test.class</exclude>\n                            <exclude>org/apache/shardingsphere/elasticjob/cloud/api/JobBootstrap.class</exclude>\n                        </excludes>\n                    </instrumentation>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n                <version>${jacoco-maven-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>prepare-agent</goal>\n                        </goals>\n                    </execution>\n                    <execution>\n                        <id>report</id>\n                        <goals>\n                            <goal>report</goal>\n                        </goals>\n                        <phase>test</phase>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n    \n    <reporting>\n        <plugins>\n            <plugin>\n                <artifactId>maven-project-info-reports-plugin</artifactId>\n                <version>${maven-project-info-reports-plugin.version}</version>\n                <configuration>\n                    <dependencyLocationsEnabled>false</dependencyLocationsEnabled>\n                </configuration>\n            </plugin>\n            <plugin>\n                <artifactId>maven-jxr-plugin</artifactId>\n                <version>${maven-jxr-plugin.version}</version>\n                <reportSets>\n                    <reportSet>\n                        <id>aggregate</id>\n                        <reports>\n                            <report>aggregate</report>\n                        </reports>\n                        <inherited>false</inherited>\n                    </reportSet>\n                </reportSets>\n            </plugin>\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>findbugs-maven-plugin</artifactId>\n                <version>${findbugs-maven-plugin.version}</version>\n                <configuration>\n                    <xmlOutput>true</xmlOutput>\n                    <effort>Max</effort>\n                </configuration>\n            </plugin>\n            <plugin>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <version>${maven-checkstyle-plugin.version}</version>\n                <configuration>\n                    <configLocation>src/resources/checkstyle.xml</configLocation>\n                    <includeTestSourceDirectory>true</includeTestSourceDirectory>\n                </configuration>\n            </plugin>\n            <plugin>\n                <artifactId>maven-pmd-plugin</artifactId>\n                <version>${maven-pmd-plugin.version}</version>\n                <configuration>\n                    <aggregate>true</aggregate>\n                    <sourceEncoding>${project.build.sourceEncoding}</sourceEncoding>\n                    <targetJdk>${java.version}</targetJdk>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>jdepend-maven-plugin</artifactId>\n                <version>${jdepend-maven-plugin.version}</version>\n            </plugin>\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>taglist-maven-plugin</artifactId>\n                <version>${taglist-maven-plugin.version}</version>\n                <configuration>\n                    <aggregate>true</aggregate>\n                </configuration>\n            </plugin>\n        </plugins>\n    </reporting>\n    \n    <url>http://shardingsphere.apache.org/elasticjob/</url>\n    \n    <licenses>\n        <license>\n            <name>Apache License 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n    \n    <mailingLists>\n        <mailingList>\n            <name>ShardingSphere Developer List</name>\n            <subscribe>dev-subscribe@shardingsphere.apache.org</subscribe>\n            <unsubscribe>dev-unsubscribe@shardingsphere.apache.org</unsubscribe>\n            <post>dev@shardingsphere.apache.org</post>\n        </mailingList>\n    </mailingLists>\n    \n    <scm>\n        <connection>scm:git:https://github.com/apache/shardingsphere-elasticjob.git</connection>\n        <developerConnection>scm:git:https://github.com/apache/shardingsphere-elasticjob.git</developerConnection>\n        <url>https://github.com/apache/shardingsphere-elasticjob.git</url>\n        <tag>HEAD</tag>\n    </scm>\n    \n    <profiles>\n        <profile>\n            <id>jdk11+</id>\n            <activation>\n                <jdk>[11,)</jdk>\n            </activation>\n            <build>\n                <pluginManagement>\n                    <plugins>\n                        <plugin>\n                            <artifactId>maven-surefire-plugin</artifactId>\n                            <configuration>\n                                <argLine>@{argLine} --add-opens java.base/java.lang.reflect=ALL-UNNAMED</argLine>\n                            </configuration>\n                        </plugin>\n                    </plugins>\n                </pluginManagement>\n            </build>\n        </profile>\n        <profile>\n            <id>check</id>\n            <build>\n                <pluginManagement>\n                    <plugins>\n                        <plugin>\n                            <groupId>org.apache.rat</groupId>\n                            <artifactId>apache-rat-plugin</artifactId>\n                            <version>${apache-rat-plugin.version}</version>\n                            <configuration>\n                                <excludes>\n                                    <exclude>**/target/**</exclude>\n                                    <exclude>**/logs/**</exclude>\n                                    <exclude>**/*.log</exclude>\n                                    <!-- IDE files -->\n                                    <exclude>**/*.iml</exclude>\n                                    <exclude>**/.idea/**</exclude>\n                                    <exclude>**/*.classpath</exclude>\n                                    <exclude>**/.project</exclude>\n                                    <exclude>**/.settings/**</exclude>\n                                    <exclude>**/dependency-reduced-pom.xml</exclude>\n                                    <!-- git files -->\n                                    <exclude>**/.gitignore</exclude>\n                                    <exclude>**/.gitmodules</exclude>\n                                    <exclude>**/.git/**</exclude>\n                                    <!-- CI files -->\n                                    <exclude>**/.travis.yml</exclude>\n                                    <exclude>**/.mvn/jvm.config</exclude>\n                                    <exclude>**/.mvn/wrapper/maven-wrapper.properties</exclude>\n                                    <!-- GitHub files -->\n                                    <exclude>**/.github/**</exclude>\n                                    <!-- document files -->\n                                    <exclude>**/*.md</exclude>\n                                    <excldue>**/*.MD</excldue>\n                                    <exclude>**/*.txt</exclude>\n                                    <exclude>**/docs/**</exclude>\n                                    <!-- UI files -->\n                                    <exclude>**/.babelrc</exclude>\n                                    <exclude>**/.editorconfig</exclude>\n                                    <exclude>**/.eslintignore</exclude>\n                                    <exclude>**/package.json</exclude>\n                                    <exclude>**/assets/**</exclude>\n                                    <exclude>**/dist/**</exclude>\n                                    <exclude>**/etc/**</exclude>\n                                    <exclude>**/node/**</exclude>\n                                    <exclude>**/node_modules/**</exclude>\n                                    <exclude>**/test/coverage/**</exclude>\n                                    <exclude>**/package-lock.json</exclude>\n                                    <!-- example files -->\n                                    <exclude>/examples/**</exclude>\n                                    <!-- GraalVM Reachability Metadata is not in JSON5 format.-->\n                                    <exclude>**/META-INF/native-image/**/*.json</exclude>\n                                    <!-- to be determined -->\n                                    <exclude>**/AdminLTE/**</exclude>\n                                    <exclude>**/bootstrap/**</exclude>\n                                    <exclude>**/bootstrap-table/**</exclude>\n                                    <exclude>**/daterangepicker/**</exclude>\n                                    <exclude>**/font-awesome-4.5.0/**</exclude>\n                                    <exclude>**/input-mask/**</exclude>\n                                    <exclude>**/finput-mask/**</exclude>\n                                    <exclude>**/jquery/**</exclude>\n                                    <exclude>**/jQuery/**</exclude>\n                                    <exclude>**/highcharts/**</exclude>\n                                </excludes>\n                            </configuration>\n                            <executions>\n                                <execution>\n                                    <goals>\n                                        <goal>check</goal>\n                                    </goals>\n                                    <phase>verify</phase>\n                                </execution>\n                            </executions>\n                        </plugin>\n                        <plugin>\n                            <artifactId>maven-checkstyle-plugin</artifactId>\n                            <version>${maven-checkstyle-plugin.version}</version>\n                            <configuration>\n                                <configLocation>src/resources/checkstyle.xml</configLocation>\n                                <includeTestSourceDirectory>true</includeTestSourceDirectory>\n                            </configuration>\n                        </plugin>\n                        <plugin>\n                            <groupId>com.diffplug.spotless</groupId>\n                            <artifactId>spotless-maven-plugin</artifactId>\n                            <version>${spotless-maven-plugin.version}</version>\n                            <configuration>\n                                <java>\n                                    <eclipse>\n                                        <!--suppress MavenModelInspection -->\n                                        <file>${maven.multiModuleProjectDirectory}/src/resources/spotless/java.xml</file>\n                                    </eclipse>\n                                    <licenseHeader>\n                                        <!--suppress MavenModelInspection -->\n                                        <file>${maven.multiModuleProjectDirectory}/src/resources/spotless/copyright.txt</file>\n                                    </licenseHeader>\n                                </java>\n                                <pom>\n                                    <sortPom>\n                                        <encoding>UTF-8</encoding>\n                                        <nrOfIndentSpace>4</nrOfIndentSpace>\n                                        <keepBlankLines>true</keepBlankLines>\n                                        <indentBlankLines>true</indentBlankLines>\n                                        <indentSchemaLocation>false</indentSchemaLocation>\n                                        <spaceBeforeCloseEmptyElement>true</spaceBeforeCloseEmptyElement>\n                                        <sortModules>false</sortModules>\n                                        <sortExecutions>false</sortExecutions>\n                                        <predefinedSortOrder>custom_1</predefinedSortOrder>\n                                        <expandEmptyElements>false</expandEmptyElements>\n                                        <sortProperties>false</sortProperties>\n                                    </sortPom>\n                                    <replace>\n                                        <name>Leading blank line</name>\n                                        <search>--&gt;\n&lt;project</search>\n                                        <replacement>--&gt;\n\n&lt;project</replacement>\n                                    </replace>\n                                </pom>\n                            </configuration>\n                        </plugin>\n                    </plugins>\n                </pluginManagement>\n                <plugins>\n                    <plugin>\n                        <groupId>org.apache.rat</groupId>\n                        <artifactId>apache-rat-plugin</artifactId>\n                    </plugin>\n                    <plugin>\n                        <artifactId>maven-checkstyle-plugin</artifactId>\n                        <version>${maven-checkstyle-plugin.version}</version>\n                        <executions>\n                            <execution>\n                                <id>validate</id>\n                                <goals>\n                                    <goal>check</goal>\n                                </goals>\n                                <phase>validate</phase>\n                            </execution>\n                        </executions>\n                    </plugin>\n                    <plugin>\n                        <groupId>com.diffplug.spotless</groupId>\n                        <artifactId>spotless-maven-plugin</artifactId>\n                        <executions>\n                            <execution>\n                                <goals>\n                                    <goal>apply</goal>\n                                </goals>\n                                <phase>compile</phase>\n                            </execution>\n                        </executions>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n        <profile>\n            <id>generateMetadata</id>\n            <build>\n                <pluginManagement>\n                    <plugins>\n                        <plugin>\n                            <artifactId>maven-surefire-plugin</artifactId>\n                            <configuration>\n                                <includes>\n                                    <include>org.apache.shardingsphere.elasticjob.test.natived.**</include>\n                                </includes>\n                            </configuration>\n                        </plugin>\n                        <plugin>\n                            <groupId>org.graalvm.buildtools</groupId>\n                            <artifactId>native-maven-plugin</artifactId>\n                            <version>${native-maven-plugin.version}</version>\n                            <extensions>true</extensions>\n                            <configuration>\n                                <agent>\n                                    <enabled>true</enabled>\n                                    <defaultMode>Conditional</defaultMode>\n                                    <modes>\n                                        <conditional>\n                                            <userCodeFilterPath>${user.dir}/test/native/native-image-filter/user-code-filter.json</userCodeFilterPath>\n                                            <extraFilterPath>${user.dir}/test/native/native-image-filter/extra-filter.json</extraFilterPath>\n                                            <parallel>true</parallel>\n                                        </conditional>\n                                    </modes>\n                                    <metadataCopy>\n                                        <disabledStages>\n                                            <stage>main</stage>\n                                        </disabledStages>\n                                        <merge>false</merge>\n                                        <outputDirectory>${user.dir}/reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/</outputDirectory>\n                                    </metadataCopy>\n                                </agent>\n                            </configuration>\n                            <executions>\n                                <execution>\n                                    <id>build-native</id>\n                                    <goals>\n                                        <goal>compile-no-fork</goal>\n                                    </goals>\n                                    <phase>package</phase>\n                                </execution>\n                                <execution>\n                                    <id>test-native</id>\n                                    <goals>\n                                        <goal>test</goal>\n                                    </goals>\n                                    <phase>test</phase>\n                                </execution>\n                            </executions>\n                        </plugin>\n                    </plugins>\n                </pluginManagement>\n            </build>\n        </profile>\n        <profile>\n            <id>nativeTestInElasticJob</id>\n            <build>\n                <pluginManagement>\n                    <plugins>\n                        <plugin>\n                            <artifactId>maven-surefire-plugin</artifactId>\n                            <configuration>\n                                <includes>\n                                    <include>org.apache.shardingsphere.elasticjob.test.natived.**</include>\n                                </includes>\n                            </configuration>\n                        </plugin>\n                        <plugin>\n                            <groupId>org.graalvm.buildtools</groupId>\n                            <artifactId>native-maven-plugin</artifactId>\n                            <version>${native-maven-plugin.version}</version>\n                            <extensions>true</extensions>\n                            <configuration>\n                                <quickBuild>true</quickBuild>\n                            </configuration>\n                            <executions>\n                                <execution>\n                                    <id>test-native</id>\n                                    <goals>\n                                        <goal>test</goal>\n                                    </goals>\n                                    <phase>test</phase>\n                                </execution>\n                            </executions>\n                        </plugin>\n                        <plugin>\n                            <groupId>org.springframework.boot</groupId>\n                            <artifactId>spring-boot-maven-plugin</artifactId>\n                            <version>${spring-boot-dependencies.version}</version>\n                            <executions>\n                                <execution>\n                                    <id>process-test-aot</id>\n                                    <goals>\n                                        <goal>process-test-aot</goal>\n                                    </goals>\n                                </execution>\n                            </executions>\n                        </plugin>\n                    </plugins>\n                </pluginManagement>\n            </build>\n        </profile>\n    </profiles>\n    \n</project>\n"
  },
  {
    "path": "reachability-metadata/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-reachability-metadata</artifactId>\n    <name>${project.artifactId}</name>\n    \n</project>\n"
  },
  {
    "path": "reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-reachability-metadata/reflect-config.json",
    "content": "[\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfiguration\",\n  \"allPublicMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.schedule.LiteJob\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.schedule.LiteJob\",\n  \"allDeclaredMethods\": true,\n  \"allDeclaredConstructors\": true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.infra.yaml.representer.ElasticJobYamlRepresenter\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfiguration\",\n  \"allPublicMethods\":true\n}\n]\n"
  },
  {
    "path": "reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/elasticjob-reachability-metadata/resource-config.json",
    "content": "{\n  \"resources\":{\n  \"includes\":[{\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.ExecutorServiceReloader\"},\n    \"pattern\":\".*META-INF/services/org\\\\.apache\\\\.shardingsphere\\\\.elasticjob\\\\..+\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.sql.SQLPropertiesFactory\"},\n    \"pattern\":\".*META-INF/sql/.+\\\\.properties$\"\n  }]},\n  \"bundles\":[]\n}\n"
  },
  {
    "path": "reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/jni-config.json",
    "content": "[\n]"
  },
  {
    "path": "reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/predefined-classes-config.json",
    "content": "[\n  {\n    \"type\":\"agent-extracted\",\n    \"classes\":[\n    ]\n  }\n]\n"
  },
  {
    "path": "reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/proxy-config.json",
    "content": "[\n  {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.tracing.ElasticJobTracingConfiguration$RDBTracingConfiguration\"},\n    \"interfaces\":[\"java.sql.Connection\"]\n  }\n]"
  },
  {
    "path": "reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/reflect-config.json",
    "content": "[\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.converter.RDBTracingStorageConfigurationConverter\"},\n  \"name\":\"[Lcom.zaxxer.hikari.util.ConcurrentBag$IConcurrentBagEntry;\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository\"},\n  \"name\":\"[Lcom.zaxxer.hikari.util.ConcurrentBag$IConcurrentBagEntry;\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.tracing.ElasticJobTracingConfiguration$RDBTracingConfiguration\"},\n  \"name\":\"[Ljava.sql.Statement;\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository\"},\n  \"name\":\"[Ljava.sql.Statement;\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap\"},\n  \"name\":\"java.util.Properties\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.ElasticJobExecutor\"},\n  \"name\":\"java.util.Properties\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverListenerManager\"},\n  \"name\":\"java.util.Properties\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.reconcile.ReconcileService\"},\n  \"name\":\"java.util.Properties\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingListenerManager$ListenServersChangedJobListener\"},\n  \"name\":\"java.util.Properties\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingListenerManager$ShardingTotalCountChangedJobListener\"},\n  \"name\":\"java.util.Properties\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"java.util.Properties\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.item.JobItemExecutorFactory\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.dataflow.executor.DataflowJobExecutor\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.error.handler.JobErrorHandlerReloader\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.error.handler.normal.IgnoreJobErrorHandler\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.error.handler.JobErrorHandlerReloader\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.error.handler.normal.LogJobErrorHandler\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.error.handler.JobErrorHandlerReloader\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.error.handler.normal.ThrowJobErrorHandler\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.http.executor.HttpJobExecutor\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.ExecutorServiceReloader\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.type.CPUUsageJobExecutorThreadPoolSizeProvider\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.ExecutorServiceReloader\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.type.SingleThreadJobExecutorThreadPoolSizeProvider\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Properties\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.ElasticJobExecutor\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Properties\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.facade.JobFacade\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"getCron\",\"parameterTypes\":[] }, {\"name\":\"getDescription\",\"parameterTypes\":[] }, {\"name\":\"getJobErrorHandlerType\",\"parameterTypes\":[] }, {\"name\":\"getJobExecutorThreadPoolSizeProviderType\",\"parameterTypes\":[] }, {\"name\":\"getJobExtraConfigurations\",\"parameterTypes\":[] }, {\"name\":\"getJobListenerTypes\",\"parameterTypes\":[] }, {\"name\":\"getJobName\",\"parameterTypes\":[] }, {\"name\":\"getJobParameter\",\"parameterTypes\":[] }, {\"name\":\"getJobShardingStrategyType\",\"parameterTypes\":[] }, {\"name\":\"getLabel\",\"parameterTypes\":[] }, {\"name\":\"getMaxTimeDiffSeconds\",\"parameterTypes\":[] }, {\"name\":\"getProps\",\"parameterTypes\":[] }, {\"name\":\"getReconcileIntervalMinutes\",\"parameterTypes\":[] }, {\"name\":\"getShardingItemParameters\",\"parameterTypes\":[] }, {\"name\":\"getShardingTotalCount\",\"parameterTypes\":[] }, {\"name\":\"getTimeZone\",\"parameterTypes\":[] }, {\"name\":\"isDisabled\",\"parameterTypes\":[] }, {\"name\":\"isFailover\",\"parameterTypes\":[] }, {\"name\":\"isMisfire\",\"parameterTypes\":[] }, {\"name\":\"isMonitorExecution\",\"parameterTypes\":[] }, {\"name\":\"isOverwrite\",\"parameterTypes\":[] }, {\"name\":\"isStaticSharding\",\"parameterTypes\":[] }, {\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDescription\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDisabled\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setFailover\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setJobExtraConfigurations\",\"parameterTypes\":[\"java.util.Collection\"] }, {\"name\":\"setJobName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobParameter\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setMaxTimeDiffSeconds\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setMisfire\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setMonitorExecution\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setOverwrite\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setReconcileIntervalMinutes\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setShardingItemParameters\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setShardingTotalCount\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setStaticSharding\",\"parameterTypes\":[\"boolean\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverListenerManager\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Properties\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverListenerManager$FailoverSettingsChangedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDescription\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDisabled\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setFailover\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setJobExtraConfigurations\",\"parameterTypes\":[\"java.util.Collection\"] }, {\"name\":\"setJobName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobParameter\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobShardingStrategyType\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setMaxTimeDiffSeconds\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setMisfire\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setMonitorExecution\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setOverwrite\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setReconcileIntervalMinutes\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setShardingItemParameters\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setShardingTotalCount\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setStaticSharding\",\"parameterTypes\":[\"boolean\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverListenerManager$JobCrashedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setJobShardingStrategyType\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.reconcile.ReconcileService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobShardingStrategyType\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Properties\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduler\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionContextService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ExecutionService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.MonitorExecutionListenerManager$MonitorExecutionSettingsChangedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDescription\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDisabled\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setFailover\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setJobExtraConfigurations\",\"parameterTypes\":[\"java.util.Collection\"] }, {\"name\":\"setJobName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobParameter\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobShardingStrategyType\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setMaxTimeDiffSeconds\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setMisfire\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setMonitorExecution\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setOverwrite\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setReconcileIntervalMinutes\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setShardingItemParameters\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setShardingTotalCount\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setStaticSharding\",\"parameterTypes\":[\"boolean\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingListenerManager$ListenServersChangedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobShardingStrategyType\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Properties\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingListenerManager$ShardingTotalCountChangedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDescription\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDisabled\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setFailover\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setJobExtraConfigurations\",\"parameterTypes\":[\"java.util.Collection\"] }, {\"name\":\"setJobName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobParameter\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobShardingStrategyType\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setMaxTimeDiffSeconds\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setMisfire\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setMonitorExecution\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setOverwrite\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Properties\"] }, {\"name\":\"setReconcileIntervalMinutes\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setShardingItemParameters\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setShardingTotalCount\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setStaticSharding\",\"parameterTypes\":[\"boolean\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"methods\":[{\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.lifecycle.internal.settings.JobConfigurationAPIImpl\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"getCron\",\"parameterTypes\":[] }, {\"name\":\"getDescription\",\"parameterTypes\":[] }, {\"name\":\"getJobErrorHandlerType\",\"parameterTypes\":[] }, {\"name\":\"getJobExecutorThreadPoolSizeProviderType\",\"parameterTypes\":[] }, {\"name\":\"getJobExtraConfigurations\",\"parameterTypes\":[] }, {\"name\":\"getJobListenerTypes\",\"parameterTypes\":[] }, {\"name\":\"getJobName\",\"parameterTypes\":[] }, {\"name\":\"getJobParameter\",\"parameterTypes\":[] }, {\"name\":\"getJobShardingStrategyType\",\"parameterTypes\":[] }, {\"name\":\"getLabel\",\"parameterTypes\":[] }, {\"name\":\"getMaxTimeDiffSeconds\",\"parameterTypes\":[] }, {\"name\":\"getProps\",\"parameterTypes\":[] }, {\"name\":\"getReconcileIntervalMinutes\",\"parameterTypes\":[] }, {\"name\":\"getShardingItemParameters\",\"parameterTypes\":[] }, {\"name\":\"getShardingTotalCount\",\"parameterTypes\":[] }, {\"name\":\"getTimeZone\",\"parameterTypes\":[] }, {\"name\":\"isDisabled\",\"parameterTypes\":[] }, {\"name\":\"isFailover\",\"parameterTypes\":[] }, {\"name\":\"isMisfire\",\"parameterTypes\":[] }, {\"name\":\"isMonitorExecution\",\"parameterTypes\":[] }, {\"name\":\"isOverwrite\",\"parameterTypes\":[] }, {\"name\":\"isStaticSharding\",\"parameterTypes\":[] }, {\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDescription\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDisabled\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setFailover\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setJobExtraConfigurations\",\"parameterTypes\":[\"java.util.Collection\"] }, {\"name\":\"setJobName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobParameter\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setMaxTimeDiffSeconds\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setMisfire\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setMonitorExecution\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setOverwrite\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setReconcileIntervalMinutes\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setShardingItemParameters\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setShardingTotalCount\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setStaticSharding\",\"parameterTypes\":[\"boolean\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.JobStatisticsAPIImpl\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDescription\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setDisabled\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setFailover\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setJobExtraConfigurations\",\"parameterTypes\":[\"java.util.Collection\"] }, {\"name\":\"setJobName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setJobParameter\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setMaxTimeDiffSeconds\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setMisfire\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setMonitorExecution\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setOverwrite\",\"parameterTypes\":[\"boolean\"] }, {\"name\":\"setReconcileIntervalMinutes\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setShardingItemParameters\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setShardingTotalCount\",\"parameterTypes\":[\"int\"] }, {\"name\":\"setStaticSharding\",\"parameterTypes\":[\"boolean\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\",\n  \"queryAllPublicMethods\":true,\n  \"methods\":[{\"name\":\"setCron\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Properties\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJOBeanInfo\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJOCustomizer\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobShutdownHookPlugin\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduler\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobShutdownHookPlugin\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setCleanShutdown\",\"parameterTypes\":[\"boolean\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobShutdownHookPlugin\",\n  \"queryAllPublicMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobShutdownHookPluginBeanInfo\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobShutdownHookPluginCustomizer\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceNode\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"getJobInstanceId\",\"parameterTypes\":[] }, {\"name\":\"getLabels\",\"parameterTypes\":[] }, {\"name\":\"getServerIp\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.instance.InstanceService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setJobInstanceId\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setServerIp\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setJobInstanceId\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setServerIp\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.lifecycle.internal.operate.JobOperateAPIImpl\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setJobInstanceId\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setServerIp\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.JobStatisticsAPIImpl\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setJobInstanceId\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setServerIp\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.ServerStatisticsAPIImpl\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setJobInstanceId\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setServerIp\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.ShardingStatisticsAPIImpl\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setJobInstanceId\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setServerIp\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstance\",\n  \"queryAllPublicMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstanceBeanInfo\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.JobInstanceCustomizer\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type.AverageAllocationJobShardingStrategy\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type.OdevitySortByNameJobShardingStrategy\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.type.RoundRobinByNameJobShardingStrategy\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setTracingStorageConfiguration\",\"parameterTypes\":[\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingStorageConfiguration\"] }, {\"name\":\"setType\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverListenerManager$FailoverSettingsChangedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setTracingStorageConfiguration\",\"parameterTypes\":[\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingStorageConfiguration\"] }, {\"name\":\"setType\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.MonitorExecutionListenerManager$MonitorExecutionSettingsChangedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setTracingStorageConfiguration\",\"parameterTypes\":[\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingStorageConfiguration\"] }, {\"name\":\"setType\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingListenerManager$ShardingTotalCountChangedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setTracingStorageConfiguration\",\"parameterTypes\":[\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingStorageConfiguration\"] }, {\"name\":\"setType\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.lifecycle.internal.settings.JobConfigurationAPIImpl\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setTracingStorageConfiguration\",\"parameterTypes\":[\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingStorageConfiguration\"] }, {\"name\":\"setType\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.JobStatisticsAPIImpl\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setTracingStorageConfiguration\",\"parameterTypes\":[\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingStorageConfiguration\"] }, {\"name\":\"setType\",\"parameterTypes\":[\"java.lang.String\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfiguration\",\n  \"queryAllPublicMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfigurationBeanInfo\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfigurationConverter\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingConfigurationCustomizer\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.yaml.YamlTracingStorageConfiguration\",\n  \"queryAllPublicMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.reg.exception.RegExceptionHandler\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.reg.zookeeper.exception.ZookeeperCuratorIgnoredExceptionProvider\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.script.executor.ScriptJobExecutor\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.item.JobItemExecutorFactory\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.simple.executor.SimpleJobExecutor\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListener\",\n  \"queryAllDeclaredMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfiguration\",\n  \"queryAllPublicMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.setup.JobClassNameProviderFactory\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.spring.core.setup.SpringProxyJobClassNameProvider\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.listener.RDBTracingListener\",\n  \"queryAllDeclaredMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.listener.RDBTracingListenerFactory\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.storage.TracingStorageConverterFactory\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.converter.RDBTracingStorageConfigurationConverter\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.DB2TracingStorageDatabaseType\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.H2TracingStorageDatabaseType\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.MySQLTracingStorageDatabaseType\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.OracleTracingStorageDatabaseType\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.PostgreSQLTracingStorageDatabaseType\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.impl.SQLServerTracingStorageDatabaseType\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.ConfigurationService\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setDataSourceClassName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Map\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.failover.FailoverListenerManager$FailoverSettingsChangedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setDataSourceClassName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Map\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.MonitorExecutionListenerManager$MonitorExecutionSettingsChangedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setDataSourceClassName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Map\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingListenerManager$ShardingTotalCountChangedJobListener\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setDataSourceClassName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Map\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.lifecycle.internal.settings.JobConfigurationAPIImpl\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setDataSourceClassName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Map\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.JobStatisticsAPIImpl\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfiguration\",\n  \"allDeclaredFields\":true,\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }, {\"name\":\"setDataSourceClassName\",\"parameterTypes\":[\"java.lang.String\"] }, {\"name\":\"setProps\",\"parameterTypes\":[\"java.util.Map\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfiguration\",\n  \"queryAllPublicMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfigurationBeanInfo\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfigurationConverter\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n  \"name\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.yaml.YamlDataSourceConfigurationCustomizer\"\n}\n]"
  },
  {
    "path": "reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/resource-config.json",
    "content": "{\n  \"resources\":{\n  \"includes\":[{\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.tracing.ElasticJobTracingConfiguration$RDBTracingConfiguration\"},\n    \"pattern\":\"\\\\QMETA-INF/services/java.sql.Driver\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.ExecutorServiceReloader\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.kernel.executor.threadpool.JobExecutorThreadPoolSizeProvider\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.setup.JobClassNameProviderFactory\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.kernel.internal.setup.JobClassNameProvider\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.sharding.ShardingService\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.kernel.internal.sharding.strategy.JobShardingStrategy\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.reg.exception.RegExceptionHandler\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.reg.exception.IgnoredExceptionProvider\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.error.handler.JobErrorHandler\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.executor.item.JobItemExecutorFactory\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.TypedJobItemExecutor\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.spi.tracing.listener.TracingListenerFactory\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.tracing.storage.TracingStorageConverterFactory\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.spi.tracing.storage.TracingStorageConfigurationConverter\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.spi.yaml.YamlConfigurationConverter\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.config.RDBTracingStorageConfiguration\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.tracing.rdb.storage.datasource.JDBCParameterDecorator\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.repository.RDBJobEventRepository\"},\n    \"pattern\":\"\\\\QMETA-INF/services/org.apache.shardingsphere.elasticjob.tracing.rdb.storage.type.TracingStorageDatabaseType\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.tracing.rdb.storage.sql.SQLPropertiesFactory\"},\n    \"pattern\":\"\\\\QMETA-INF/sql/H2.properties\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.tracing.ElasticJobTracingConfiguration$RDBTracingConfiguration\"},\n    \"pattern\":\"\\\\Qorg/h2/util/data.zip\\\\E\"\n  }, {\n    \"condition\":{\"typeReachable\":\"org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobBootstrapConfiguration\"},\n    \"pattern\":\"\\\\Qorg/quartz/core/quartz-build.properties\\\\E\"\n  }]},\n  \"bundles\":[]\n}"
  },
  {
    "path": "reachability-metadata/src/main/resources/META-INF/native-image/org.apache.shardingsphere.elasticjob/generated-reachability-metadata/serialization-config.json",
    "content": "{\n  \"types\":[\n  ],\n  \"lambdaCapturingTypes\":[\n  ],\n  \"proxies\":[\n  ]\n}"
  },
  {
    "path": "reachability-metadata/src/main/resources/META-INF/native-image/org.apache.zookeeper/zookeeper/3.9.3/reflect-config.json",
    "content": "[\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.ZooKeeper\"},\n  \"name\":\"org.apache.zookeeper.ClientCnxnSocketNIO\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[\"org.apache.zookeeper.client.ZKClientConfig\"] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.metrics.impl.MetricsProviderBootstrap\"},\n  \"name\":\"org.apache.zookeeper.metrics.impl.DefaultMetricsProvider\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.server.quorum.QuorumPeerConfig\"},\n  \"name\":\"org.apache.zookeeper.metrics.impl.DefaultMetricsProvider\"\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.server.ServerCnxnFactory\"},\n  \"name\":\"org.apache.zookeeper.server.ConnectionBean\",\n  \"queryAllPublicConstructors\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.server.ServerCnxnFactory\"},\n  \"name\":\"org.apache.zookeeper.server.ConnectionMXBean\",\n  \"queryAllPublicMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.server.ZooKeeperServer\"},\n  \"name\":\"org.apache.zookeeper.server.DataTreeBean\",\n  \"queryAllPublicConstructors\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.server.ZooKeeperServer\"},\n  \"name\":\"org.apache.zookeeper.server.DataTreeMXBean\",\n  \"queryAllPublicMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.server.ServerCnxnFactory\"},\n  \"name\":\"org.apache.zookeeper.server.NIOServerCnxnFactory\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.server.ZooKeeperServer\"},\n  \"name\":\"org.apache.zookeeper.server.ZooKeeperServerBean\",\n  \"queryAllPublicConstructors\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.server.ZooKeeperServer\"},\n  \"name\":\"org.apache.zookeeper.server.ZooKeeperServerMXBean\",\n  \"queryAllPublicMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.apache.zookeeper.server.watch.WatchManagerFactory\"},\n  \"name\":\"org.apache.zookeeper.server.watch.WatchManager\",\n  \"methods\":[{\"name\":\"<init>\",\"parameterTypes\":[] }]\n}\n]\n"
  },
  {
    "path": "reachability-metadata/src/main/resources/META-INF/native-image/org.hamcrest/hamcrest/2.2/reflect-config.json",
    "content": "[\n{\n  \"condition\":{\"typeReachable\":\"org.hamcrest.internal.ReflectiveTypeFinder\"},\n  \"name\":\"org.hamcrest.core.StringStartsWith\",\n  \"queryAllDeclaredMethods\":true\n},\n{\n  \"condition\":{\"typeReachable\":\"org.hamcrest.internal.ReflectiveTypeFinder\"},\n  \"name\":\"org.hamcrest.core.SubstringMatcher\",\n  \"queryAllDeclaredMethods\":true\n}\n]\n"
  },
  {
    "path": "registry-center/api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-registry-center</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-registry-center-api</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere</groupId>\n            <artifactId>shardingsphere-infra-spi</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/base/CoordinatorRegistryCenter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.base;\n\nimport org.apache.shardingsphere.elasticjob.reg.base.transaction.TransactionOperation;\nimport org.apache.shardingsphere.elasticjob.reg.listener.ConnectionStateChangedEventListener;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\n\nimport java.util.List;\nimport java.util.concurrent.Executor;\n\n/**\n * Coordinator registry center.\n */\npublic interface CoordinatorRegistryCenter extends RegistryCenter {\n    \n    /**\n     * Get value from registry center directly.\n     * \n     * @param key key\n     * @return value\n     */\n    String getDirectly(String key);\n    \n    /**\n     * Get children keys.\n     * \n     * @param key key\n     * @return children keys\n     */\n    List<String> getChildrenKeys(String key);\n    \n    /**\n     * Get children number.\n     *\n     * @param key key\n     * @return children number\n     */\n    int getNumChildren(String key);\n    \n    /**\n     * Persist ephemeral data.\n     * \n     * @param key key\n     * @param value value\n     */\n    void persistEphemeral(String key, String value);\n    \n    /**\n     * Persist sequential data.\n     *\n     * @param key key\n     * @param value value\n     * @return value which include 10 digital\n     */\n    String persistSequential(String key, String value);\n    \n    /**\n     * Persist ephemeral sequential data.\n     * \n     * @param key key\n     */\n    void persistEphemeralSequential(String key);\n    \n    /**\n     * Add data to cache.\n     * \n     * @param cachePath cache path\n     */\n    void addCacheData(String cachePath);\n    \n    /**\n     * Evict data from cache.\n     *\n     * @param cachePath cache path\n     */\n    void evictCacheData(String cachePath);\n    \n    /**\n     * Get raw cache object of registry center.\n     * \n     * @param cachePath cache path\n     * @return raw cache object of registry center\n     */\n    Object getRawCache(String cachePath);\n    \n    /**\n     * Execute in leader.\n     *\n     * @param key key\n     * @param callback callback of leader\n     */\n    void executeInLeader(String key, LeaderExecutionCallback callback);\n    \n    /**\n     * Watch changes of a key.\n     *\n     * @param key key to be watched\n     * @param listener data listener\n     * @param executor event notify executor\n     */\n    void watch(String key, DataChangedEventListener listener, Executor executor);\n    \n    /**\n     * Add connection state changed event listener to registry center.\n     *\n     * @param key key to be watched.\n     * @param listener connection state changed event listener\n     */\n    void addConnectionStateChangedEventListener(String key, ConnectionStateChangedEventListener listener);\n    \n    /**\n     * Execute operations in transaction.\n     *\n     * @param transactionOperations operations\n     * @throws Exception exception\n     */\n    void executeInTransaction(List<TransactionOperation> transactionOperations) throws Exception;\n    \n    /**\n     * Remove all data listeners that have been bound to the current key.\n     * @param key key to be watched\n     */\n    void removeDataListeners(String key);\n    \n    /**\n     * Remove conn state listener that have been bound to the current key.\n     * @param key key to be watched\n     */\n    void removeConnStateListener(String key);\n}\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/base/ElectionCandidate.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.base;\n\n/**\n * Election candidate.\n * \n * <p>\n *     Guarantee {@link #startLeadership()} and {@link #stopLeadership()} method run in same thread.\n * </p>\n */\npublic interface ElectionCandidate {\n    \n    /**\n     * Start leadership.\n     * \n     * @throws Exception exception\n     */\n    void startLeadership() throws Exception;\n    \n    /**\n     * Stop leadership.\n     * \n     * <p>Should not throw any exception for the implementation class.</p>\n     */\n    void stopLeadership();\n}\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/base/LeaderExecutionCallback.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.base;\n\n/**\n * Leader server execution callback.\n */\npublic interface LeaderExecutionCallback {\n    \n    /**\n     * Execute after leader elected.\n     */\n    void execute();\n}\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/base/RegistryCenter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.base;\n\n/**\n * Registry center.\n */\npublic interface RegistryCenter {\n    \n    /**\n     * Initialize registry center.\n     */\n    void init();\n    \n    /**\n     * Close registry center.\n     */\n    void close();\n    \n    /**\n     * Get value.\n     * \n     * @param key key\n     * @return value\n     */\n    String get(String key);\n    \n    /**\n     * Judge node is exist or not.\n     * \n     * @param key key\n     * @return node is exist or not\n     */\n    boolean isExisted(String key);\n    \n    /**\n     * Persist data.\n     * \n     * @param key key\n     * @param value value\n     */\n    void persist(String key, String value);\n    \n    /**\n     * Update data.\n     * \n     * @param key key\n     * @param value value\n     */\n    void update(String key, String value);\n    \n    /**\n     * Remove data.\n     * \n     * @param key key\n     */\n    void remove(String key);\n    \n    /**\n     * Get current time from registry center.\n     * \n     * @param key key\n     * @return current time from registry center\n     */\n    long getRegistryCenterTime(String key);\n    \n    /**\n     * Get raw client for registry center client.\n     ** \n     * @return registry center raw client\n     */\n    Object getRawClient();\n}\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/base/transaction/TransactionOperation.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.base.transaction;\n\nimport lombok.AccessLevel;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.ToString;\n\n@RequiredArgsConstructor(access = AccessLevel.PRIVATE)\n@Getter\n@ToString\npublic final class TransactionOperation {\n    \n    public enum Type {\n        \n        CHECK_EXISTS,\n        \n        ADD,\n        \n        UPDATE,\n        \n        DELETE\n    }\n    \n    private final Type type;\n    \n    private final String key;\n    \n    private final String value;\n    \n    /**\n     * Operation add.\n     *\n     * @param key key\n     * @param value value\n     * @return TransactionOperation\n     */\n    public static TransactionOperation opAdd(final String key, final String value) {\n        return new TransactionOperation(Type.ADD, key, value);\n    }\n    \n    /**\n     * Operation update.\n     *\n     * @param key key\n     * @param value value\n     * @return TransactionOperation\n     */\n    public static TransactionOperation opUpdate(final String key, final String value) {\n        return new TransactionOperation(Type.UPDATE, key, value);\n    }\n    \n    /**\n     * Operation delete.\n     *\n     * @param key key\n     * @return TransactionOperation\n     */\n    public static TransactionOperation opDelete(final String key) {\n        return new TransactionOperation(Type.DELETE, key, null);\n    }\n    \n    /**\n     * Operation check exists.\n     *\n     * @param key key\n     * @return TransactionOperation\n     */\n    public static TransactionOperation opCheckExists(final String key) {\n        return new TransactionOperation(Type.CHECK_EXISTS, key, null);\n    }\n}\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/exception/IgnoredExceptionProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.exception;\n\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\n\nimport java.util.Collection;\n\n/**\n * Ignored exception provider.\n */\n@SingletonSPI\npublic interface IgnoredExceptionProvider {\n    \n    /**\n     * Get ignored exceptions.\n     *\n     * @return ignored exceptions\n     */\n    Collection<Class<? extends Throwable>> getIgnoredExceptions();\n}\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/exception/RegException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.exception;\n\n/**\n * Registry center exception.\n */\npublic final class RegException extends RuntimeException {\n    \n    private static final long serialVersionUID = -6417179023552012152L;\n    \n    public RegException(final Exception cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/exception/RegExceptionHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.exception;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;\n\n/**\n * Registry center exception handler.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\n@Slf4j\npublic final class RegExceptionHandler {\n    \n    /**\n     * Handle exception.\n     * \n     * @param cause exception to be handled\n     */\n    public static void handleException(final Exception cause) {\n        if (null == cause) {\n            return;\n        }\n        if (isIgnoredException(cause) || null != cause.getCause() && isIgnoredException(cause.getCause())) {\n            log.debug(\"Elastic job: ignored exception for: {}\", cause.getMessage());\n        } else if (cause instanceof InterruptedException) {\n            Thread.currentThread().interrupt();\n        } else {\n            throw new RegException(cause);\n        }\n    }\n    \n    private static boolean isIgnoredException(final Throwable cause) {\n        return ShardingSphereServiceLoader.getServiceInstances(IgnoredExceptionProvider.class).stream().flatMap(each -> each.getIgnoredExceptions().stream()).anyMatch(each -> each.isInstance(cause));\n    }\n}\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/listener/ConnectionStateChangedEventListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.listener;\n\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\n\n/**\n * Connection state changed event listener.\n */\npublic interface ConnectionStateChangedEventListener {\n    \n    enum State {\n        \n        CONNECTED,\n        \n        RECONNECTED,\n        \n        UNAVAILABLE\n    }\n    \n    /**\n     * Invoke if connection state of registry center changed.\n     *\n     * @param registryCenter registry center\n     * @param newState new state\n     */\n    void onStateChanged(CoordinatorRegistryCenter registryCenter, State newState);\n}\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/listener/DataChangedEvent.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.listener;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\n\n/**\n * Data changed event.\n */\n@RequiredArgsConstructor\n@Getter\npublic final class DataChangedEvent {\n    \n    private final Type type;\n    \n    private final String key;\n    \n    private final String value;\n    \n    /**\n     * Data changed type.\n     */\n    public enum Type {\n        \n        ADDED, UPDATED, DELETED, IGNORED\n    }\n}\n"
  },
  {
    "path": "registry-center/api/src/main/java/org/apache/shardingsphere/elasticjob/reg/listener/DataChangedEventListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.listener;\n\n/**\n * Data changed listener.\n */\npublic interface DataChangedEventListener {\n    \n    /**\n     * Fire when data changed.\n     *\n     * @param event data changed event\n     */\n    void onChange(DataChangedEvent event);\n}\n"
  },
  {
    "path": "registry-center/api/src/test/java/org/apache/shardingsphere/elasticjob/reg/base/transaction/TransactionOperationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.base.transaction;\n\nimport org.apache.shardingsphere.elasticjob.reg.base.transaction.TransactionOperation.Type;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass TransactionOperationTest {\n    \n    @Test\n    void assertOpAdd() {\n        TransactionOperation actual = TransactionOperation.opAdd(\"key\", \"value\");\n        assertThat(actual.getType(), is(Type.ADD));\n        assertThat(actual.getKey(), is(\"key\"));\n        assertThat(actual.getValue(), is(\"value\"));\n    }\n    \n    @Test\n    void assertOpUpdate() {\n        TransactionOperation actual = TransactionOperation.opUpdate(\"key\", \"value\");\n        assertThat(actual.getType(), is(Type.UPDATE));\n        assertThat(actual.getKey(), is(\"key\"));\n        assertThat(actual.getValue(), is(\"value\"));\n    }\n    \n    @Test\n    void assertOpDelete() {\n        TransactionOperation actual = TransactionOperation.opDelete(\"key\");\n        assertThat(actual.getType(), is(Type.DELETE));\n        assertThat(actual.getKey(), is(\"key\"));\n    }\n    \n    @Test\n    void assertOpCheckExists() {\n        TransactionOperation actual = TransactionOperation.opCheckExists(\"key\");\n        assertThat(actual.getType(), is(Type.CHECK_EXISTS));\n        assertThat(actual.getKey(), is(\"key\"));\n    }\n}\n"
  },
  {
    "path": "registry-center/api/src/test/java/org/apache/shardingsphere/elasticjob/reg/exception/RegExceptionHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.exception;\n\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass RegExceptionHandlerTest {\n    \n    @Test\n    @Disabled\n    // TODO throw InterruptedException will cause zookeeper TestingServer break. Ignore first, fix it later.\n    void assertHandleExceptionWithInterruptedException() {\n        RegExceptionHandler.handleException(new InterruptedException());\n    }\n    \n    @Test\n    void assertHandleExceptionWithNull() {\n        RegExceptionHandler.handleException(null);\n    }\n    \n    @Test\n    void assertHandleExceptionWithOtherException() {\n        assertThrows(RegException.class, () -> RegExceptionHandler.handleException(new RuntimeException()));\n    }\n}\n"
  },
  {
    "path": "registry-center/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-registry-center</artifactId>\n    <packaging>pom</packaging>\n    <name>${project.artifactId}</name>\n    \n    <modules>\n        <module>api</module>\n        <module>provider</module>\n    </modules>\n</project>\n"
  },
  {
    "path": "registry-center/provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-registry-center</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-regitry-center-provider</artifactId>\n    <packaging>pom</packaging>\n    <name>${project.artifactId}</name>\n    \n    <modules>\n        <module>zookeeper-curator</module>\n    </modules>\n</project>\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-regitry-center-provider</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-registry-center-zookeeper-curator</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-registry-center-api</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-test-util</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-framework</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-client</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-recipes</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.awaitility</groupId>\n            <artifactId>awaitility</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/main/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.Setter;\n\n/**\n * Zookeeper configuration.\n */\n@Getter\n@Setter\n@RequiredArgsConstructor\npublic final class ZookeeperConfiguration {\n    \n    /**\n     * Server list of ZooKeeper.\n     * \n     * <p>\n     * Include IP addresses and ports,\n     * Multiple IP address split by comma.\n     * For example: host1:2181,host2:2181\n     * </p>\n     */\n    private final String serverLists;\n    \n    /**\n     * Namespace.\n     */\n    private final String namespace;\n    \n    /**\n     * Base sleep time milliseconds. \n     */\n    private int baseSleepTimeMilliseconds = 1000;\n    \n    /**\n     * Max sleep time milliseconds.\n     */\n    private int maxSleepTimeMilliseconds = 3000;\n    \n    /**\n     * Max retry times.\n     */\n    private int maxRetries = 3;\n    \n    /**\n     * Session timeout milliseconds.\n     */\n    private int sessionTimeoutMilliseconds;\n    \n    /**\n     * Connection timeout milliseconds.\n     */\n    private int connectionTimeoutMilliseconds;\n    \n    /**\n     * Zookeeper digest.\n     */\n    private String digest;\n    \n    /**\n     * Allows configuring if the ensemble configuration changes are watched.\n     * If the HA enabled Zookeeper clusters are hidden under a virtual IP of Kubernetes,\n     * the Zookeeper Client can return a URL during Ensemble Tracking,\n     * which will cause an unresolved host exception within the Curator Framework.\n     * At the ElasticJob level, this will cause a cluster restart.\n     *\n     * @see org.apache.curator.framework.CuratorFrameworkFactory.Builder#ensembleTracker(boolean)\n     */\n    private boolean ensembleTracker = true;\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/main/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperElectionService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.recipes.leader.LeaderSelector;\nimport org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter;\nimport org.apache.shardingsphere.elasticjob.reg.base.ElectionCandidate;\nimport org.apache.shardingsphere.elasticjob.reg.exception.RegException;\n\nimport java.util.concurrent.CountDownLatch;\n\n/**\n * Use {@link LeaderSelector} to implement election service.\n */\n@Slf4j\npublic final class ZookeeperElectionService {\n    \n    private final CountDownLatch leaderLatch = new CountDownLatch(1);\n    \n    private final LeaderSelector leaderSelector;\n    \n    public ZookeeperElectionService(final String identity, final CuratorFramework client, final String electionPath, final ElectionCandidate electionCandidate) {\n        leaderSelector = new LeaderSelector(client, electionPath, new LeaderSelectorListenerAdapter() {\n            \n            @Override\n            public void takeLeadership(final CuratorFramework client) throws Exception {\n                log.info(\"Elastic job: {} has leadership\", identity);\n                try {\n                    electionCandidate.startLeadership();\n                    leaderLatch.await();\n                    log.warn(\"Elastic job: {} lost leadership.\", identity);\n                    electionCandidate.stopLeadership();\n                } catch (final RegException exception) {\n                    log.error(\"Elastic job: Starting error\", exception);\n                    System.exit(1);\n                }\n            }\n        });\n        leaderSelector.autoRequeue();\n        leaderSelector.setId(identity);\n    }\n    \n    /**\n     * Start election.\n     */\n    public void start() {\n        log.debug(\"Elastic job: {} start to elect leadership\", leaderSelector.getId());\n        leaderSelector.start();\n    }\n    \n    /**\n     * Stop election.\n     */\n    public void stop() {\n        log.info(\"Elastic job: stop leadership election\");\n        leaderLatch.countDown();\n        try {\n            leaderSelector.close();\n            // CHECKSTYLE:OFF\n        } catch (final Exception ignore) {\n        }\n        // CHECKSTYLE:ON\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/main/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport lombok.AccessLevel;\nimport lombok.Getter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.framework.api.ACLProvider;\nimport org.apache.curator.framework.api.transaction.CuratorOp;\nimport org.apache.curator.framework.api.transaction.TransactionOp;\nimport org.apache.curator.framework.recipes.cache.ChildData;\nimport org.apache.curator.framework.recipes.cache.CuratorCache;\nimport org.apache.curator.framework.recipes.cache.CuratorCacheListener;\nimport org.apache.curator.framework.recipes.leader.LeaderLatch;\nimport org.apache.curator.framework.state.ConnectionStateListener;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.utils.CloseableUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.base.LeaderExecutionCallback;\nimport org.apache.shardingsphere.elasticjob.reg.base.transaction.TransactionOperation;\nimport org.apache.shardingsphere.elasticjob.reg.exception.RegException;\nimport org.apache.shardingsphere.elasticjob.reg.exception.RegExceptionHandler;\nimport org.apache.shardingsphere.elasticjob.reg.listener.ConnectionStateChangedEventListener;\nimport org.apache.shardingsphere.elasticjob.reg.listener.ConnectionStateChangedEventListener.State;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent.Type;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEventListener;\nimport org.apache.zookeeper.CreateMode;\nimport org.apache.zookeeper.KeeperException;\nimport org.apache.zookeeper.ZooDefs;\nimport org.apache.zookeeper.data.ACL;\nimport org.apache.zookeeper.data.Stat;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Registry center of ZooKeeper.\n */\n@Slf4j\npublic final class ZookeeperRegistryCenter implements CoordinatorRegistryCenter {\n    \n    @Getter(AccessLevel.PROTECTED)\n    private final ZookeeperConfiguration zkConfig;\n    \n    private final Map<String, CuratorCache> caches = new ConcurrentHashMap<>();\n    \n    /**\n     * Data listener list.\n     */\n    private final Map<String, List<CuratorCacheListener>> dataListeners = new ConcurrentHashMap<>();\n    \n    /**\n     * Connections state listener list.\n     */\n    private final Map<String, List<ConnectionStateListener>> connStateListeners = new ConcurrentHashMap<>();\n    \n    @Getter\n    private CuratorFramework client;\n    \n    public ZookeeperRegistryCenter(final ZookeeperConfiguration zkConfig) {\n        this.zkConfig = zkConfig;\n    }\n    \n    @Override\n    public void init() {\n        log.debug(\"Elastic job: zookeeper registry center init, server lists is: {}.\", zkConfig.getServerLists());\n        CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()\n                .connectString(zkConfig.getServerLists())\n                .retryPolicy(new ExponentialBackoffRetry(zkConfig.getBaseSleepTimeMilliseconds(), zkConfig.getMaxRetries(), zkConfig.getMaxSleepTimeMilliseconds()))\n                .ensembleTracker(zkConfig.isEnsembleTracker())\n                .namespace(zkConfig.getNamespace());\n        if (0 != zkConfig.getSessionTimeoutMilliseconds()) {\n            builder.sessionTimeoutMs(zkConfig.getSessionTimeoutMilliseconds());\n        }\n        if (0 != zkConfig.getConnectionTimeoutMilliseconds()) {\n            builder.connectionTimeoutMs(zkConfig.getConnectionTimeoutMilliseconds());\n        }\n        if (!Strings.isNullOrEmpty(zkConfig.getDigest())) {\n            builder.authorization(\"digest\", zkConfig.getDigest().getBytes(StandardCharsets.UTF_8))\n                    .aclProvider(new ACLProvider() {\n                        \n                        @Override\n                        public List<ACL> getDefaultAcl() {\n                            return ZooDefs.Ids.CREATOR_ALL_ACL;\n                        }\n                        \n                        @Override\n                        public List<ACL> getAclForPath(final String path) {\n                            return ZooDefs.Ids.CREATOR_ALL_ACL;\n                        }\n                    });\n        }\n        client = builder.build();\n        client.start();\n        try {\n            if (!client.blockUntilConnected(zkConfig.getMaxSleepTimeMilliseconds() * zkConfig.getMaxRetries(), TimeUnit.MILLISECONDS)) {\n                client.close();\n                throw new KeeperException.OperationTimeoutException();\n            }\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n    }\n    \n    @Override\n    public void close() {\n        for (Entry<String, CuratorCache> each : caches.entrySet()) {\n            each.getValue().close();\n        }\n        waitForCacheClose();\n        CloseableUtils.closeQuietly(client);\n    }\n    \n    /*\n     * // TODO sleep 500ms, let cache client close first and then client, otherwise will throw exception reference：https://issues.apache.org/jira/browse/CURATOR-157\n     */\n    private void waitForCacheClose() {\n        try {\n            Thread.sleep(500L);\n        } catch (final InterruptedException ex) {\n            Thread.currentThread().interrupt();\n        }\n    }\n    \n    @Override\n    public String get(final String key) {\n        CuratorCache cache = findCuratorCache(key);\n        if (null == cache) {\n            return getDirectly(key);\n        }\n        Optional<ChildData> resultInCache = cache.get(key);\n        return resultInCache.map(v -> null == v.getData() ? null : new String(v.getData(), StandardCharsets.UTF_8)).orElseGet(() -> getDirectly(key));\n    }\n    \n    private CuratorCache findCuratorCache(final String key) {\n        for (Entry<String, CuratorCache> entry : caches.entrySet()) {\n            if (key.startsWith(entry.getKey())) {\n                return entry.getValue();\n            }\n        }\n        return null;\n    }\n    \n    @Override\n    public String getDirectly(final String key) {\n        try {\n            return new String(client.getData().forPath(key), StandardCharsets.UTF_8);\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n            return null;\n        }\n    }\n    \n    @Override\n    public List<String> getChildrenKeys(final String key) {\n        try {\n            List<String> result = client.getChildren().forPath(key);\n            result.sort(Comparator.reverseOrder());\n            return result;\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n            return Collections.emptyList();\n        }\n    }\n    \n    @Override\n    public int getNumChildren(final String key) {\n        try {\n            Stat stat = client.checkExists().forPath(key);\n            if (null != stat) {\n                return stat.getNumChildren();\n            }\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n        return 0;\n    }\n    \n    @Override\n    public boolean isExisted(final String key) {\n        try {\n            return null != client.checkExists().forPath(key);\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n            return false;\n        }\n    }\n    \n    @Override\n    public void persist(final String key, final String value) {\n        try {\n            if (!isExisted(key)) {\n                client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(key, value.getBytes(StandardCharsets.UTF_8));\n            } else {\n                update(key, value);\n            }\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n    }\n    \n    @Override\n    public void update(final String key, final String value) {\n        try {\n            TransactionOp transactionOp = client.transactionOp();\n            client.transaction().forOperations(transactionOp.check().forPath(key), transactionOp.setData().forPath(key, value.getBytes(StandardCharsets.UTF_8)));\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n    }\n    \n    @Override\n    public void persistEphemeral(final String key, final String value) {\n        try {\n            if (isExisted(key)) {\n                client.delete().deletingChildrenIfNeeded().forPath(key);\n            }\n            client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(key, value.getBytes(StandardCharsets.UTF_8));\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n    }\n    \n    @Override\n    public String persistSequential(final String key, final String value) {\n        try {\n            return client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath(key, value.getBytes(StandardCharsets.UTF_8));\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n        return null;\n    }\n    \n    @Override\n    public void persistEphemeralSequential(final String key) {\n        try {\n            client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(key);\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n    }\n    \n    @Override\n    public void remove(final String key) {\n        try {\n            client.delete().deletingChildrenIfNeeded().forPath(key);\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n    }\n    \n    @Override\n    public long getRegistryCenterTime(final String key) {\n        long result = 0L;\n        try {\n            persist(key, \"\");\n            result = client.checkExists().forPath(key).getMtime();\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n        Preconditions.checkState(0L != result, \"Cannot get registry center time.\");\n        return result;\n    }\n    \n    @Override\n    public Object getRawClient() {\n        return client;\n    }\n    \n    @Override\n    public void addConnectionStateChangedEventListener(final String key,\n                                                       final ConnectionStateChangedEventListener listener) {\n        CoordinatorRegistryCenter coordinatorRegistryCenter = this;\n        ConnectionStateListener connStateListener = (client, newState) -> {\n            State state;\n            switch (newState) {\n                case CONNECTED:\n                    state = State.CONNECTED;\n                    break;\n                case LOST:\n                case SUSPENDED:\n                    state = State.UNAVAILABLE;\n                    break;\n                case RECONNECTED:\n                    state = State.RECONNECTED;\n                    break;\n                case READ_ONLY:\n                default:\n                    throw new IllegalStateException(\"Illegal registry center connection state: \" + newState);\n            }\n            listener.onStateChanged(coordinatorRegistryCenter, state);\n        };\n        client.getConnectionStateListenable().addListener(connStateListener);\n        connStateListeners.computeIfAbsent(key, k -> new LinkedList<>()).add(connStateListener);\n    }\n    \n    @Override\n    public void executeInTransaction(final List<TransactionOperation> transactionOperations) throws Exception {\n        client.transaction().forOperations(toCuratorOps(transactionOperations));\n    }\n    \n    private List<CuratorOp> toCuratorOps(final List<TransactionOperation> transactionOperations) {\n        List<CuratorOp> result = new ArrayList<>(transactionOperations.size());\n        TransactionOp transactionOp = client.transactionOp();\n        for (TransactionOperation each : transactionOperations) {\n            result.add(toCuratorOp(each, transactionOp));\n        }\n        return result;\n    }\n    \n    private CuratorOp toCuratorOp(final TransactionOperation each, final TransactionOp transactionOp) {\n        try {\n            switch (each.getType()) {\n                case CHECK_EXISTS:\n                    return transactionOp.check().forPath(each.getKey());\n                case ADD:\n                    return transactionOp.create().forPath(each.getKey(), each.getValue().getBytes(StandardCharsets.UTF_8));\n                case UPDATE:\n                    return transactionOp.setData().forPath(each.getKey(), each.getValue().getBytes(StandardCharsets.UTF_8));\n                case DELETE:\n                    return transactionOp.delete().forPath(each.getKey());\n                default:\n                    throw new UnsupportedOperationException(each.toString());\n            }\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            throw new RegException(ex);\n        }\n    }\n    \n    @Override\n    public void addCacheData(final String cachePath) {\n        CuratorCache cache = CuratorCache.build(client, cachePath);\n        try {\n            cache.start();\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            RegExceptionHandler.handleException(ex);\n        }\n        caches.put(cachePath + \"/\", cache);\n    }\n    \n    @Override\n    public void evictCacheData(final String cachePath) {\n        CuratorCache cache = caches.remove(cachePath + \"/\");\n        if (null != cache) {\n            cache.close();\n        }\n    }\n    \n    @Override\n    public Object getRawCache(final String cachePath) {\n        return caches.get(cachePath + \"/\");\n    }\n    \n    @Override\n    public void executeInLeader(final String key, final LeaderExecutionCallback callback) {\n        try (LeaderLatch latch = new LeaderLatch(client, key)) {\n            latch.start();\n            latch.await();\n            callback.execute();\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            handleException(ex);\n        }\n    }\n    \n    @Override\n    public void watch(final String key, final DataChangedEventListener listener, final Executor executor) {\n        CuratorCache cache = caches.get(key + \"/\");\n        CuratorCacheListener cacheListener = (curatorType, oldData, newData) -> {\n            if (null == newData && null == oldData) {\n                return;\n            }\n            Type type = getTypeFromCuratorType(curatorType);\n            String path = Type.DELETED == type ? oldData.getPath() : newData.getPath();\n            if (path.isEmpty() || Type.IGNORED == type) {\n                return;\n            }\n            byte[] data = Type.DELETED == type ? oldData.getData() : newData.getData();\n            listener.onChange(new DataChangedEvent(type, path, null == data ? \"\" : new String(data, StandardCharsets.UTF_8)));\n        };\n        if (executor != null) {\n            cache.listenable().addListener(cacheListener, executor);\n        } else {\n            cache.listenable().addListener(cacheListener);\n        }\n        dataListeners.computeIfAbsent(key, k -> new LinkedList<>()).add(cacheListener);\n    }\n    \n    @Override\n    public void removeDataListeners(final String key) {\n        final CuratorCache cache = caches.get(key + \"/\");\n        if (Objects.isNull(cache)) {\n            dataListeners.remove(key);\n            return;\n        }\n        List<CuratorCacheListener> cacheListenerList = dataListeners.remove(key);\n        if (Objects.isNull(cacheListenerList)) {\n            return;\n        }\n        cacheListenerList.forEach(listener -> cache.listenable().removeListener(listener));\n    }\n    \n    @Override\n    public void removeConnStateListener(final String key) {\n        final List<ConnectionStateListener> listenerList = connStateListeners.remove(key);\n        if (Objects.isNull(listenerList)) {\n            return;\n        }\n        listenerList.forEach(listener -> client.getConnectionStateListenable().removeListener(listener));\n    }\n    \n    private Type getTypeFromCuratorType(final CuratorCacheListener.Type curatorType) {\n        switch (curatorType) {\n            case NODE_CREATED:\n                return Type.ADDED;\n            case NODE_DELETED:\n                return Type.DELETED;\n            case NODE_CHANGED:\n                return Type.UPDATED;\n            default:\n                return Type.IGNORED;\n        }\n    }\n    \n    private void handleException(final Exception ex) {\n        if (ex instanceof InterruptedException) {\n            Thread.currentThread().interrupt();\n        } else {\n            throw new RegException(ex);\n        }\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/main/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/exception/ZookeeperCuratorIgnoredExceptionProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper.exception;\n\nimport org.apache.shardingsphere.elasticjob.reg.exception.IgnoredExceptionProvider;\nimport org.apache.zookeeper.KeeperException.ConnectionLossException;\nimport org.apache.zookeeper.KeeperException.NoNodeException;\nimport org.apache.zookeeper.KeeperException.NodeExistsException;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\n/**\n * Zookeeper curator ignored exception provider.\n */\npublic final class ZookeeperCuratorIgnoredExceptionProvider implements IgnoredExceptionProvider {\n    \n    @Override\n    public Collection<Class<? extends Throwable>> getIgnoredExceptions() {\n        return Arrays.asList(ConnectionLossException.class, NoNodeException.class, NodeExistsException.class);\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.reg.exception.IgnoredExceptionProvider",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.reg.zookeeper.exception.ZookeeperCuratorIgnoredExceptionProvider\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.curator.test.InstanceSpec;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass ZookeeperConfigurationTest {\n    \n    @Test\n    void assertNewZookeeperConfigurationForServerListsAndNamespace() {\n        int randomPort = InstanceSpec.getRandomPort();\n        ZookeeperConfiguration zkConfig = new ZookeeperConfiguration(\"localhost:\" + randomPort, \"myNamespace\");\n        assertThat(zkConfig.getServerLists(), is(\"localhost:\" + randomPort));\n        assertThat(zkConfig.getNamespace(), is(\"myNamespace\"));\n        assertThat(zkConfig.getBaseSleepTimeMilliseconds(), is(1000));\n        assertThat(zkConfig.getMaxSleepTimeMilliseconds(), is(3000));\n        assertThat(zkConfig.getMaxRetries(), is(3));\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperElectionServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.framework.recipes.leader.LeaderSelector;\nimport org.apache.curator.retry.RetryOneTime;\nimport org.apache.curator.test.InstanceSpec;\nimport org.apache.curator.test.KillSession;\nimport org.apache.shardingsphere.elasticjob.reg.base.ElectionCandidate;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Supplier;\n\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass ZookeeperElectionServiceTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static final int RANDOM_PORT = InstanceSpec.getRandomPort();\n    \n    private static final String HOST_AND_PORT = \"localhost:\" + RANDOM_PORT;\n    \n    private static final String ELECTION_PATH = \"/election\";\n    \n    @Mock\n    private ElectionCandidate electionCandidate;\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @Test\n    void assertContend() throws Exception {\n        CuratorFramework client = CuratorFrameworkFactory.newClient(EMBED_TESTING_SERVER.getConnectionString(), new RetryOneTime(2000));\n        client.start();\n        client.blockUntilConnected();\n        ZookeeperElectionService service = new ZookeeperElectionService(HOST_AND_PORT, client, ELECTION_PATH, electionCandidate);\n        service.start();\n        ElectionCandidate anotherElectionCandidate = mock(ElectionCandidate.class);\n        CuratorFramework anotherClient = CuratorFrameworkFactory.newClient(EMBED_TESTING_SERVER.getConnectionString(), new RetryOneTime(2000));\n        ZookeeperElectionService anotherService = new ZookeeperElectionService(\"ANOTHER_CLIENT:\" + RANDOM_PORT, anotherClient, ELECTION_PATH, anotherElectionCandidate);\n        anotherClient.start();\n        anotherClient.blockUntilConnected();\n        anotherService.start();\n        KillSession.kill(client.getZookeeperClient().getZooKeeper());\n        service.stop();\n        blockUntilCondition(() -> hasLeadership(anotherService));\n        ((CountDownLatch) ReflectionUtils.getFieldValue(anotherService, \"leaderLatch\")).countDown();\n        blockUntilCondition(() -> !hasLeadership(anotherService));\n        anotherService.stop();\n        verify(anotherElectionCandidate, atLeastOnce()).startLeadership();\n        verify(anotherElectionCandidate, atLeastOnce()).stopLeadership();\n    }\n    \n    private void blockUntilCondition(final Supplier<Boolean> condition) {\n        Awaitility.await().pollDelay(100L, TimeUnit.MILLISECONDS).until(condition::get);\n    }\n    \n    private boolean hasLeadership(final ZookeeperElectionService zookeeperElectionService) {\n        return ((LeaderSelector) ReflectionUtils.getFieldValue(zookeeperElectionService, \"leaderSelector\")).hasLeadership();\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenterExecuteInLeaderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.reg.base.LeaderExecutionCallback;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.Timeout;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nclass ZookeeperRegistryCenterExecuteInLeaderTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static ZookeeperRegistryCenter zkRegCenter;\n    \n    @BeforeAll\n    static void setUp() {\n        EMBED_TESTING_SERVER.start();\n        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), ZookeeperRegistryCenterExecuteInLeaderTest.class.getName());\n        zkRegCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        zookeeperConfiguration.setConnectionTimeoutMilliseconds(30000);\n        zkRegCenter.init();\n    }\n    \n    @AfterAll\n    static void tearDown() {\n        zkRegCenter.close();\n    }\n    \n    @Test\n    @Timeout(value = 10000L, unit = TimeUnit.MILLISECONDS)\n    void assertExecuteInLeader() throws InterruptedException {\n        final int threads = 10;\n        CountDownLatch countDownLatch = new CountDownLatch(threads);\n        SerialOnlyExecutionCallback serialOnlyExecutionCallback = new SerialOnlyExecutionCallback(countDownLatch, Thread.currentThread());\n        ExecutorService executorService = Executors.newFixedThreadPool(threads);\n        for (int i = 0; i < threads; i++) {\n            executorService.execute(() -> zkRegCenter.executeInLeader(\"/leader\", serialOnlyExecutionCallback));\n        }\n        executorService.shutdown();\n        countDownLatch.await();\n    }\n    \n    @RequiredArgsConstructor\n    private static class SerialOnlyExecutionCallback implements LeaderExecutionCallback {\n        \n        private final AtomicBoolean executing = new AtomicBoolean(false);\n        \n        private final CountDownLatch countDownLatch;\n        \n        private final Thread waitingThread;\n        \n        @Override\n        public void execute() {\n            if (executing.get() || !executing.compareAndSet(false, true)) {\n                handleConcurrentExecution();\n            }\n            try {\n                Thread.sleep(100L);\n            } catch (final InterruptedException ex) {\n                waitingThread.interrupt();\n            }\n            countDownLatch.countDown();\n            if (!executing.compareAndSet(true, false)) {\n                handleConcurrentExecution();\n            }\n        }\n        \n        private void handleConcurrentExecution() {\n            waitingThread.interrupt();\n            throw new IllegalStateException(\"Callback is executing concurrently\");\n        }\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenterForAuthTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.retry.RetryOneTime;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.env.RegistryCenterEnvironmentPreparer;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.apache.zookeeper.KeeperException.NoAuthException;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass ZookeeperRegistryCenterForAuthTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static final String NAME_SPACE = ZookeeperRegistryCenterForAuthTest.class.getName();\n    \n    private static ZookeeperRegistryCenter zkRegCenter;\n    \n    @BeforeAll\n    static void setUp() {\n        EMBED_TESTING_SERVER.start();\n        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), NAME_SPACE);\n        zookeeperConfiguration.setDigest(\"digest:password\");\n        zookeeperConfiguration.setSessionTimeoutMilliseconds(5000);\n        zookeeperConfiguration.setConnectionTimeoutMilliseconds(5000);\n        zkRegCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        zkRegCenter.init();\n        RegistryCenterEnvironmentPreparer.persist(zkRegCenter);\n    }\n    \n    @AfterAll\n    static void tearDown() {\n        zkRegCenter.close();\n    }\n    \n    @Test\n    void assertInitWithDigestSuccess() throws Exception {\n        try (\n                CuratorFramework client = CuratorFrameworkFactory.builder()\n                        .connectString(EMBED_TESTING_SERVER.getConnectionString())\n                        .retryPolicy(new RetryOneTime(2000))\n                        .authorization(\"digest\", \"digest:password\".getBytes()).build()) {\n            client.start();\n            client.blockUntilConnected();\n            assertThat(client.getData().forPath(\"/\" + ZookeeperRegistryCenterForAuthTest.class.getName() + \"/test/deep/nested\"), is(\"deepNested\".getBytes()));\n        }\n    }\n    \n    @Test\n    void assertInitWithDigestFailure() {\n        assertThrows(NoAuthException.class, () -> {\n            try (CuratorFramework client = CuratorFrameworkFactory.newClient(EMBED_TESTING_SERVER.getConnectionString(), new RetryOneTime(2000))) {\n                client.start();\n                client.blockUntilConnected();\n                client.getData().forPath(\"/\" + ZookeeperRegistryCenterForAuthTest.class.getName() + \"/test/deep/nested\");\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenterInitFailureTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.curator.test.InstanceSpec;\nimport org.apache.shardingsphere.elasticjob.reg.exception.RegException;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass ZookeeperRegistryCenterInitFailureTest {\n    \n    @Test\n    void assertInitFailure() {\n        assertThrows(RegException.class, () -> {\n            ZookeeperRegistryCenter zkRegCenter =\n                    new ZookeeperRegistryCenter(new ZookeeperConfiguration(\"localhost:\" + InstanceSpec.getRandomPort(), ZookeeperRegistryCenterInitFailureTest.class.getName()));\n            zkRegCenter.init();\n        });\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenterListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.listen.Listenable;\nimport org.apache.curator.framework.recipes.cache.CuratorCache;\nimport org.apache.curator.framework.recipes.cache.CuratorCacheListener;\nimport org.apache.curator.framework.state.ConnectionStateListener;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.mockito.Mockito.any;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass ZookeeperRegistryCenterListenerTest {\n    \n    @Mock\n    private Map<String, CuratorCache> caches;\n    \n    @Mock\n    private CuratorFramework client;\n    \n    @Mock\n    private CuratorCache cache;\n    \n    @Mock\n    private Listenable<ConnectionStateListener> connStateListenable;\n    \n    @Mock\n    private Listenable<CuratorCacheListener> dataListenable;\n    \n    private ZookeeperRegistryCenter regCenter;\n    \n    private final String jobPath = \"/test_job\";\n    \n    @BeforeEach\n    void setUp() {\n        regCenter = new ZookeeperRegistryCenter(null);\n        ReflectionUtils.setFieldValue(regCenter, \"caches\", caches);\n        ReflectionUtils.setFieldValue(regCenter, \"client\", client);\n    }\n    \n    @Test\n    void testAddConnectionStateChangedEventListener() {\n        when(client.getConnectionStateListenable()).thenReturn(connStateListenable);\n        regCenter.addConnectionStateChangedEventListener(jobPath, null);\n        verify(client.getConnectionStateListenable()).addListener(any());\n        assertEquals(1, getConnStateListeners().get(jobPath).size());\n    }\n    \n    @Test\n    void testWatch() {\n        when(caches.get(jobPath + \"/\")).thenReturn(cache);\n        when(cache.listenable()).thenReturn(dataListenable);\n        regCenter.watch(jobPath, null, null);\n        verify(cache.listenable()).addListener(any());\n        assertEquals(1, getDataListeners().get(jobPath).size());\n    }\n    \n    @Test\n    void testRemoveDataListenersNonCache() {\n        when(cache.listenable()).thenReturn(dataListenable);\n        regCenter.removeDataListeners(jobPath);\n        verify(cache.listenable(), never()).removeListener(any());\n        assertNull(getDataListeners().get(jobPath));\n    }\n    \n    @Test\n    void testRemoveDataListenersHasCache() {\n        when(caches.get(jobPath + \"/\")).thenReturn(cache);\n        when(cache.listenable()).thenReturn(dataListenable);\n        List<CuratorCacheListener> list = new ArrayList<>();\n        list.add(null);\n        list.add(null);\n        getDataListeners().put(jobPath, list);\n        regCenter.removeDataListeners(jobPath);\n        assertNull(getDataListeners().get(jobPath));\n        verify(cache.listenable(), times(2)).removeListener(null);\n    }\n    \n    @Test\n    void testRemoveDataListenersHasCacheEmptyListeners() {\n        when(caches.get(jobPath + \"/\")).thenReturn(cache);\n        when(cache.listenable()).thenReturn(dataListenable);\n        regCenter.removeDataListeners(jobPath);\n        assertNull(getDataListeners().get(jobPath));\n        verify(cache.listenable(), never()).removeListener(null);\n    }\n    \n    @Test\n    void testRemoveConnStateListener() {\n        when(client.getConnectionStateListenable()).thenReturn(connStateListenable);\n        List<ConnectionStateListener> list = new ArrayList<>();\n        list.add(null);\n        list.add(null);\n        getConnStateListeners().put(jobPath, list);\n        assertEquals(2, getConnStateListeners().get(jobPath).size());\n        regCenter.removeConnStateListener(jobPath);\n        assertNull(getConnStateListeners().get(jobPath));\n        verify(client.getConnectionStateListenable(), times(2)).removeListener(null);\n    }\n    \n    @Test\n    void testRemoveConnStateListenerEmptyListeners() {\n        when(client.getConnectionStateListenable()).thenReturn(connStateListenable);\n        regCenter.removeConnStateListener(jobPath);\n        assertNull(getConnStateListeners().get(jobPath));\n        verify(client.getConnectionStateListenable(), never()).removeListener(null);\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    private Map<String, List<ConnectionStateListener>> getConnStateListeners() {\n        return (Map<String, List<ConnectionStateListener>>) ReflectionUtils.getFieldValue(regCenter, \"connStateListeners\");\n    }\n    \n    @SuppressWarnings(\"unchecked\")\n    private Map<String, List<CuratorCacheListener>> getDataListeners() {\n        return (Map<String, List<CuratorCacheListener>>) ReflectionUtils.getFieldValue(regCenter, \"dataListeners\");\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenterMiscellaneousTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.recipes.cache.CuratorCache;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.instanceOf;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass ZookeeperRegistryCenterMiscellaneousTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static ZookeeperConfiguration zookeeperConfiguration;\n    \n    private static ZookeeperRegistryCenter zkRegCenter;\n    \n    @BeforeAll\n    static void setUp() {\n        EMBED_TESTING_SERVER.start();\n        zookeeperConfiguration = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), ZookeeperRegistryCenterMiscellaneousTest.class.getName());\n        zookeeperConfiguration.setConnectionTimeoutMilliseconds(30000);\n        zkRegCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        zkRegCenter.init();\n        zkRegCenter.addCacheData(\"/test\");\n    }\n    \n    @AfterAll\n    static void tearDown() {\n        zkRegCenter.close();\n    }\n    \n    @Test\n    void assertGetRawClient() {\n        assertThat(zkRegCenter.getRawClient(), instanceOf(CuratorFramework.class));\n        assertThat(((CuratorFramework) zkRegCenter.getRawClient()).getNamespace(), is(ZookeeperRegistryCenterMiscellaneousTest.class.getName()));\n    }\n    \n    @Test\n    void assertGetRawCache() {\n        assertThat(zkRegCenter.getRawCache(\"/test\"), instanceOf(CuratorCache.class));\n    }\n    \n    @Test\n    void assertGetZkConfig() {\n        ZookeeperRegistryCenter zkRegCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        assertThat(zkRegCenter.getZkConfig(), is(zookeeperConfiguration));\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenterModifyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.retry.RetryOneTime;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.env.RegistryCenterEnvironmentPreparer;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.List;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.startsWith;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ZookeeperRegistryCenterModifyTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static ZookeeperRegistryCenter zkRegCenter;\n    \n    @BeforeAll\n    static void setUp() {\n        EMBED_TESTING_SERVER.start();\n        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), ZookeeperRegistryCenterModifyTest.class.getName());\n        zkRegCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        zookeeperConfiguration.setConnectionTimeoutMilliseconds(30000);\n        zkRegCenter.init();\n        RegistryCenterEnvironmentPreparer.persist(zkRegCenter);\n    }\n    \n    @AfterAll\n    static void tearDown() {\n        zkRegCenter.close();\n    }\n    \n    @Test\n    void assertPersist() {\n        zkRegCenter.persist(\"/test\", \"test_update\");\n        zkRegCenter.persist(\"/persist/new\", \"new_value\");\n        assertThat(zkRegCenter.get(\"/test\"), is(\"test_update\"));\n        assertThat(zkRegCenter.get(\"/persist/new\"), is(\"new_value\"));\n    }\n    \n    @Test\n    void assertUpdate() {\n        zkRegCenter.persist(\"/update\", \"before_update\");\n        zkRegCenter.update(\"/update\", \"after_update\");\n        assertThat(zkRegCenter.getDirectly(\"/update\"), is(\"after_update\"));\n    }\n    \n    @Test\n    void assertPersistEphemeral() throws Exception {\n        zkRegCenter.persist(\"/persist\", \"persist_value\");\n        zkRegCenter.persistEphemeral(\"/ephemeral\", \"ephemeral_value\");\n        assertThat(zkRegCenter.get(\"/persist\"), is(\"persist_value\"));\n        assertThat(zkRegCenter.get(\"/ephemeral\"), is(\"ephemeral_value\"));\n        zkRegCenter.close();\n        CuratorFramework client = CuratorFrameworkFactory.newClient(EMBED_TESTING_SERVER.getConnectionString(), new RetryOneTime(2000));\n        client.start();\n        client.blockUntilConnected();\n        assertThat(client.getData().forPath(\"/\" + ZookeeperRegistryCenterModifyTest.class.getName() + \"/persist\"), is(\"persist_value\".getBytes()));\n        assertNull(client.checkExists().forPath(\"/\" + ZookeeperRegistryCenterModifyTest.class.getName() + \"/ephemeral\"));\n        zkRegCenter.init();\n    }\n    \n    @Test\n    void assertPersistSequential() throws Exception {\n        assertThat(zkRegCenter.persistSequential(\"/sequential/test_sequential\", \"test_value\"), startsWith(\"/sequential/test_sequential\"));\n        assertThat(zkRegCenter.persistSequential(\"/sequential/test_sequential\", \"test_value\"), startsWith(\"/sequential/test_sequential\"));\n        try (CuratorFramework client = CuratorFrameworkFactory.newClient(EMBED_TESTING_SERVER.getConnectionString(), new RetryOneTime(2000))) {\n            client.start();\n            client.blockUntilConnected();\n            List<String> actual = client.getChildren().forPath(\"/\" + ZookeeperRegistryCenterModifyTest.class.getName() + \"/sequential\");\n            assertThat(actual.size(), is(2));\n            for (String each : actual) {\n                assertThat(each, startsWith(\"test_sequential\"));\n                assertThat(zkRegCenter.get(\"/sequential/\" + each), startsWith(\"test_value\"));\n            }\n            zkRegCenter.remove(\"/sequential\");\n            assertFalse(zkRegCenter.isExisted(\"/sequential\"));\n        }\n    }\n    \n    @Test\n    void assertPersistEphemeralSequential() throws Exception {\n        zkRegCenter.persistEphemeralSequential(\"/sequential/test_ephemeral_sequential\");\n        zkRegCenter.persistEphemeralSequential(\"/sequential/test_ephemeral_sequential\");\n        try (CuratorFramework client = CuratorFrameworkFactory.newClient(EMBED_TESTING_SERVER.getConnectionString(), new RetryOneTime(2000))) {\n            client.start();\n            client.blockUntilConnected();\n            List<String> actual = client.getChildren().forPath(\"/\" + ZookeeperRegistryCenterModifyTest.class.getName() + \"/sequential\");\n            assertThat(actual.size(), is(2));\n            for (String each : actual) {\n                assertThat(each, startsWith(\"test_ephemeral_sequential\"));\n            }\n            zkRegCenter.close();\n            actual = client.getChildren().forPath(\"/\" + ZookeeperRegistryCenterModifyTest.class.getName() + \"/sequential\");\n            assertTrue(actual.isEmpty());\n            zkRegCenter.init();\n        }\n    }\n    \n    @Test\n    void assertRemove() {\n        zkRegCenter.remove(\"/test\");\n        assertFalse(zkRegCenter.isExisted(\"/test\"));\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenterQueryWithCacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.env.RegistryCenterEnvironmentPreparer;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\nclass ZookeeperRegistryCenterQueryWithCacheTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static ZookeeperRegistryCenter zkRegCenter;\n    \n    @BeforeAll\n    static void setUp() {\n        EMBED_TESTING_SERVER.start();\n        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), ZookeeperRegistryCenterQueryWithCacheTest.class.getName());\n        zkRegCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        zookeeperConfiguration.setConnectionTimeoutMilliseconds(30000);\n        zkRegCenter.init();\n        RegistryCenterEnvironmentPreparer.persist(zkRegCenter);\n        zkRegCenter.addCacheData(\"/test\");\n    }\n    \n    @AfterAll\n    static void tearDown() {\n        zkRegCenter.close();\n    }\n    \n    @Test\n    void assertGetWithoutValue() {\n        assertNull(zkRegCenter.get(\"/test/null\"));\n    }\n    \n    @Test\n    void assertGetFromCache() {\n        assertThat(zkRegCenter.get(\"/test\"), is(\"test\"));\n        assertThat(zkRegCenter.get(\"/test/deep/nested\"), is(\"deepNested\"));\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenterQueryWithoutCacheTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.env.RegistryCenterEnvironmentPreparer;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ZookeeperRegistryCenterQueryWithoutCacheTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static ZookeeperRegistryCenter zkRegCenter;\n    \n    @BeforeAll\n    static void setUp() {\n        EMBED_TESTING_SERVER.start();\n        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), ZookeeperRegistryCenterQueryWithoutCacheTest.class.getName());\n        zookeeperConfiguration.setConnectionTimeoutMilliseconds(30000);\n        zkRegCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        zkRegCenter.init();\n        RegistryCenterEnvironmentPreparer.persist(zkRegCenter);\n        zkRegCenter.addCacheData(\"/other\");\n    }\n    \n    @AfterAll\n    static void tearDown() {\n        zkRegCenter.close();\n    }\n    \n    @Test\n    void assertGetFromServer() {\n        assertThat(zkRegCenter.get(\"/test\"), is(\"test\"));\n        assertThat(zkRegCenter.get(\"/test/deep/nested\"), is(\"deepNested\"));\n    }\n    \n    @Test\n    void assertGetChildrenKeys() {\n        assertThat(zkRegCenter.getChildrenKeys(\"/test\"), is(Arrays.asList(\"deep\", \"child\")));\n        assertThat(zkRegCenter.getChildrenKeys(\"/test/deep\"), is(Collections.singletonList(\"nested\")));\n        assertThat(zkRegCenter.getChildrenKeys(\"/test/child\"), is(Collections.<String>emptyList()));\n        assertThat(zkRegCenter.getChildrenKeys(\"/test/notExisted\"), is(Collections.<String>emptyList()));\n    }\n    \n    @Test\n    void assertGetNumChildren() {\n        assertThat(zkRegCenter.getNumChildren(\"/test\"), is(2));\n        assertThat(zkRegCenter.getNumChildren(\"/test/deep\"), is(1));\n        assertThat(zkRegCenter.getNumChildren(\"/test/child\"), is(0));\n        assertThat(zkRegCenter.getNumChildren(\"/test/notExisted\"), is(0));\n    }\n    \n    @Test\n    void assertIsExisted() {\n        assertTrue(zkRegCenter.isExisted(\"/test\"));\n        assertTrue(zkRegCenter.isExisted(\"/test/deep/nested\"));\n        assertFalse(zkRegCenter.isExisted(\"/notExisted\"));\n    }\n    \n    @Test\n    void assertGetRegistryCenterTime() {\n        long regCenterTime = zkRegCenter.getRegistryCenterTime(\"/_systemTime/current\");\n        assertTrue(regCenterTime <= System.currentTimeMillis());\n        long updatedRegCenterTime = zkRegCenter.getRegistryCenterTime(\"/_systemTime/current\");\n        assertTrue(regCenterTime < updatedRegCenterTime);\n    }\n    \n    @Test\n    void assertGetWithoutNode() {\n        assertNull(zkRegCenter.get(\"/notExisted\"));\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenterTransactionTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.shardingsphere.elasticjob.reg.base.transaction.TransactionOperation;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.env.RegistryCenterEnvironmentPreparer;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.apache.zookeeper.KeeperException;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\n\nclass ZookeeperRegistryCenterTransactionTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static ZookeeperRegistryCenter zkRegCenter;\n    \n    @BeforeAll\n    static void setUp() {\n        EMBED_TESTING_SERVER.start();\n        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), ZookeeperRegistryCenterTransactionTest.class.getName());\n        zkRegCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        zookeeperConfiguration.setConnectionTimeoutMilliseconds(30000);\n        zkRegCenter.init();\n    }\n    \n    @BeforeEach\n    void setup() {\n        RegistryCenterEnvironmentPreparer.persist(zkRegCenter);\n    }\n    \n    @Test\n    void assertExecuteInTransactionSucceeded() throws Exception {\n        List<TransactionOperation> operations = new ArrayList<>(3);\n        operations.add(TransactionOperation.opCheckExists(\"/test\"));\n        operations.add(TransactionOperation.opCheckExists(\"/test/child\"));\n        operations.add(TransactionOperation.opCheckExists(\"/test/deep/nested\"));\n        operations.add(TransactionOperation.opAdd(\"/test/transaction\", \"transaction\"));\n        zkRegCenter.executeInTransaction(operations);\n        assertThat(zkRegCenter.getDirectly(\"/test/transaction\"), is(\"transaction\"));\n    }\n    \n    @Test\n    void assertExecuteInTransactionFailed() throws Exception {\n        List<TransactionOperation> operations = new ArrayList<>(3);\n        operations.add(TransactionOperation.opAdd(\"/test/shouldnotexists\", \"\"));\n        operations.add(TransactionOperation.opCheckExists(\"/test/notexists\"));\n        try {\n            zkRegCenter.executeInTransaction(operations);\n        } catch (KeeperException ignored) {\n        }\n        assertFalse(zkRegCenter.isExisted(\"/test/shouldnotexists\"));\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/ZookeeperRegistryCenterWatchTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper;\n\nimport org.apache.curator.utils.ThreadUtils;\nimport org.apache.shardingsphere.elasticjob.reg.listener.DataChangedEvent;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.env.RegistryCenterEnvironmentPreparer;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.Timeout;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.startsWith;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass ZookeeperRegistryCenterWatchTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static ZookeeperRegistryCenter zkRegCenter;\n    \n    @BeforeAll\n    static void setUp() {\n        EMBED_TESTING_SERVER.start();\n        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), ZookeeperRegistryCenterWatchTest.class.getName());\n        zkRegCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);\n        zookeeperConfiguration.setConnectionTimeoutMilliseconds(30000);\n        zkRegCenter.init();\n        RegistryCenterEnvironmentPreparer.persist(zkRegCenter);\n    }\n    \n    @AfterAll\n    static void tearDown() {\n        zkRegCenter.close();\n    }\n    \n    @Test\n    @Timeout(value = 10000L, unit = TimeUnit.MILLISECONDS)\n    void assertWatchWithoutExecutor() throws InterruptedException {\n        CountDownLatch waitingForCountDownValue = new CountDownLatch(1);\n        String key = \"/test-watch-without-executor\";\n        zkRegCenter.addCacheData(key);\n        CountDownLatch waitingForWatchReady = new CountDownLatch(1);\n        zkRegCenter.watch(key, event -> {\n            waitingForWatchReady.countDown();\n            if (DataChangedEvent.Type.UPDATED == event.getType() && \"countDown\".equals(event.getValue())) {\n                waitingForCountDownValue.countDown();\n            }\n        }, null);\n        zkRegCenter.persist(key, \"\");\n        waitingForWatchReady.await();\n        zkRegCenter.update(key, \"countDown\");\n        waitingForCountDownValue.await();\n    }\n    \n    @Test\n    @Timeout(value = 10000L, unit = TimeUnit.MILLISECONDS)\n    void assertWatchWithExecutor() throws InterruptedException {\n        CountDownLatch waitingForCountDownValue = new CountDownLatch(1);\n        String key = \"/test-watch-with-executor\";\n        zkRegCenter.addCacheData(key);\n        CountDownLatch waitingForWatchReady = new CountDownLatch(1);\n        String threadNamePrefix = \"ListenerNotify\";\n        ThreadFactory threadFactory = ThreadUtils.newGenericThreadFactory(threadNamePrefix);\n        ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);\n        zkRegCenter.watch(key, event -> {\n            assertThat(Thread.currentThread().getName(), startsWith(threadNamePrefix));\n            waitingForWatchReady.countDown();\n            if (DataChangedEvent.Type.UPDATED == event.getType() && \"countDown\".equals(event.getValue())) {\n                waitingForCountDownValue.countDown();\n            }\n        }, executor);\n        zkRegCenter.persist(key, \"\");\n        waitingForWatchReady.await();\n        zkRegCenter.update(key, \"countDown\");\n        waitingForCountDownValue.await();\n        executor.shutdown();\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/env/RegistryCenterEnvironmentPreparer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper.env;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class RegistryCenterEnvironmentPreparer {\n    \n    /**\n     * Persist the data to registry center.\n     *\n     * @param registryCenter ZooKeeper registry center\n     */\n    public static void persist(final ZookeeperRegistryCenter registryCenter) {\n        registryCenter.persist(\"/test\", \"test\");\n        registryCenter.persist(\"/test/deep/nested\", \"deepNested\");\n        registryCenter.persist(\"/test/child\", \"child\");\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/java/org/apache/shardingsphere/elasticjob/reg/zookeeper/exception/ZookeeperCuratorIgnoredExceptionProviderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.reg.zookeeper.exception;\n\nimport org.apache.zookeeper.KeeperException.ConnectionLossException;\nimport org.apache.zookeeper.KeeperException.NoNodeException;\nimport org.apache.zookeeper.KeeperException.NodeExistsException;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass ZookeeperCuratorIgnoredExceptionProviderTest {\n    \n    @Test\n    void assertIgnoredException() {\n        List<Class<? extends Throwable>> expected = Arrays.asList(ConnectionLossException.class, NoNodeException.class, NodeExistsException.class);\n        assertThat(new ZookeeperCuratorIgnoredExceptionProvider().getIgnoredExceptions(), is(expected));\n    }\n}\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/resources/conf/reg/local.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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/test=test\n/test/deep/nested=deepNested\n/test/child=child\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/resources/conf/reg/local_overwrite.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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/test=test_overwrite\n/test/deep/nested=deepNested_overwrite\n/new=new\n"
  },
  {
    "path": "registry-center/provider/zookeeper-curator/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n            <level>ERROR</level>\n        </filter>\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.curator.framework.recipes.leader.LeaderSelector\" level=\"OFF\" />\n</configuration>\n"
  },
  {
    "path": "restful/README.md",
    "content": "# Restful Service\n\n## Usage\n\n### Create a RestfulController\n```java\n@ContextPath(\"/job\")\npublic class JobController implements RestfulController {\n    \n    @Mapping(method = Http.POST, path = \"/{group}/{jobName}\")\n    public JobPojo createJob(@Param(name = \"group\", source = ParamSource.PATH) final String group,\n                             @Param(name = \"jobName\", source = ParamSource.PATH) final String jobName,\n                             @Param(name = \"cron\", source = ParamSource.QUERY) final String cron,\n                             @RequestBody String description) {\n        JobPojo jobPojo = new JobPojo();\n        jobPojo.setName(jobName);\n        jobPojo.setCron(cron);\n        jobPojo.setGroup(group);\n        jobPojo.setDescription(description);\n        return jobPojo;\n    }\n\n    @Mapping(method = Http.GET, pattern = \"/code/204\")\n    @Returning(code = 204)\n    public Object return204() {\n        return null;\n    }\n}\n```\n\n### (Optional) Create ExceptionHandler\n```java\npublic class CustomIllegalStateExceptionHandler implements ExceptionHandler<IllegalStateException> {\n    @Override\n    public ExceptionHandleResult handleException(final IllegalStateException ex) {\n        return ExceptionHandleResult.builder()\n                .statusCode(403)\n                .contentType(Http.DEFAULT_CONTENT_TYPE)\n                .result(ResultDto.builder().code(1).data(ex.getLocalizedMessage()).build())\n                .build();\n    }\n}\n```\n\n### Configure Restful Service and Start Up\n```java\nNettyRestfulServiceConfiguration configuration = new NettyRestfulServiceConfiguration(8080);\nconfiguration.addControllerInstance(new JobController());\nconfiguration.addExceptionHandler(IllegalStateException.class, new CustomIllegalStateExceptionHandler());\nRestfulService restfulService = new NettyRestfulService(configuration);\nrestfulService.startup();\n```\n"
  },
  {
    "path": "restful/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-restful</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-kernel</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec-http</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-jdk14</artifactId>\n            <optional>true</optional>\n        </dependency>\n    </dependencies>\n    \n    <build>\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n        </resources>\n        <testResources>\n            <testResource>\n                <directory>src/test/resources</directory>\n            </testResource>\n        </testResources>\n    </build>\n</project>\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/Filter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful;\n\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport org.apache.shardingsphere.elasticjob.restful.filter.FilterChain;\n\n/**\n * HTTP request filter.\n */\npublic interface Filter {\n    \n    /**\n     * Do filter.\n     *\n     * @param httpRequest  HTTP request\n     * @param httpResponse HTTP response\n     * @param filterChain  filter chain\n     */\n    void doFilter(FullHttpRequest httpRequest, FullHttpResponse httpResponse, FilterChain filterChain);\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/Http.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n/**\n * Constants for HTTP.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class Http {\n    \n    public static final String GET = \"GET\";\n    \n    public static final String POST = \"POST\";\n    \n    public static final String HEAD = \"HEAD\";\n    \n    public static final String PUT = \"PUT\";\n    \n    public static final String PATCH = \"PATCH\";\n    \n    public static final String OPTIONS = \"OPTIONS\";\n    \n    public static final String DELETE = \"DELETE\";\n    \n    public static final String TRACE = \"TRACE\";\n    \n    public static final String CONNECT = \"CONNECT\";\n    \n    public static final String DEFAULT_CONTENT_TYPE = \"application/json; charset=utf-8\";\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/NettyRestfulService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful;\n\nimport com.google.common.base.Strings;\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.util.NettyRuntime;\nimport lombok.RequiredArgsConstructor;\nimport lombok.SneakyThrows;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.restful.pipeline.RestfulServiceChannelInitializer;\n\n/**\n * Implemented {@link RestfulService} via Netty.\n */\n@RequiredArgsConstructor\n@Slf4j\npublic final class NettyRestfulService implements RestfulService {\n    \n    private static final int DEFAULT_WORKER_GROUP_THREADS = 1 + 2 * NettyRuntime.availableProcessors();\n    \n    private final NettyRestfulServiceConfiguration config;\n    \n    private ServerBootstrap serverBootstrap;\n    \n    private EventLoopGroup bossEventLoopGroup;\n    \n    private EventLoopGroup workerEventLoopGroup;\n    \n    private void initServerBootstrap() {\n        bossEventLoopGroup = new NioEventLoopGroup();\n        workerEventLoopGroup = new NioEventLoopGroup(DEFAULT_WORKER_GROUP_THREADS);\n        serverBootstrap = new ServerBootstrap()\n                .group(bossEventLoopGroup, workerEventLoopGroup)\n                .channel(NioServerSocketChannel.class)\n                .childHandler(new RestfulServiceChannelInitializer(config));\n    }\n    \n    @SneakyThrows(InterruptedException.class)\n    @Override\n    public void startup() {\n        initServerBootstrap();\n        ChannelFuture channelFuture;\n        if (!Strings.isNullOrEmpty(config.getHost())) {\n            channelFuture = serverBootstrap.bind(config.getHost(), config.getPort());\n        } else {\n            channelFuture = serverBootstrap.bind(config.getPort());\n        }\n        channelFuture.addListener(future -> {\n            if (future.isSuccess()) {\n                log.info(\"Restful Service started on port {}.\", config.getPort());\n            } else {\n                log.error(\"Failed to start Restful Service.\", future.cause());\n            }\n        }).sync();\n    }\n    \n    @Override\n    public void shutdown() {\n        bossEventLoopGroup.shutdownGracefully();\n        workerEventLoopGroup.shutdownGracefully();\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/NettyRestfulServiceConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful;\n\nimport com.google.common.base.Preconditions;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.restful.handler.ExceptionHandler;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Configuration for {@link NettyRestfulService}.\n */\n@RequiredArgsConstructor\n@Getter\n@Setter\npublic final class NettyRestfulServiceConfiguration {\n    \n    private final List<Filter> filterInstances = new LinkedList<>();\n    \n    private final List<RestfulController> controllerInstances = new LinkedList<>();\n    \n    private final Map<Class<? extends Throwable>, ExceptionHandler<? extends Throwable>> exceptionHandlers = new HashMap<>();\n    \n    private final int port;\n    \n    private String host;\n    \n    /**\n     * If trailing slash sensitive, <code>/foo/bar</code> is not equals to <code>/foo/bar/</code>.\n     */\n    private boolean trailingSlashSensitive;\n    \n    /**\n     * Add instances of {@link Filter}.\n     *\n     * @param instances instances of Filter\n     */\n    public void addFilterInstances(final Filter... instances) {\n        filterInstances.addAll(Arrays.asList(instances));\n    }\n    \n    /**\n     * Add instances of RestfulController.\n     *\n     * @param instances instances of RestfulController\n     */\n    public void addControllerInstances(final RestfulController... instances) {\n        controllerInstances.addAll(Arrays.asList(instances));\n    }\n    \n    /**\n     * Add an instance of ExceptionHandler for specific exception.\n     *\n     * @param exceptionType    The type of exception to handle\n     * @param exceptionHandler Instance of ExceptionHandler\n     * @param <E>              The type of exception to handle\n     */\n    public <E extends Throwable> void addExceptionHandler(final Class<E> exceptionType, final ExceptionHandler<E> exceptionHandler) {\n        Preconditions.checkState(!exceptionHandlers.containsKey(exceptionType), \"ExceptionHandler for %s has already existed.\", exceptionType.getName());\n        exceptionHandlers.put(exceptionType, exceptionHandler);\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/RestfulController.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful;\n\n/**\n * RESTFul controller.\n */\npublic interface RestfulController {\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/RestfulService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful;\n\n/**\n * A facade of restful service. Invoke startup() method to start listen a port to provide Restful API.\n */\npublic interface RestfulService {\n    \n    /**\n     * Start RESTFul service.\n     */\n    void startup();\n    \n    /**\n     * Shutdown RESTFul service.\n     */\n    void shutdown();\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/annotation/ContextPath.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.annotation;\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)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface ContextPath {\n    \n    /**\n     * Context path.\n     * Starts with '/' and no '/' at the end.\n     * Such as <code>/api/app</code>.\n     *\n     * @return Context path\n     */\n    String value();\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/annotation/Mapping.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Declare what HTTP method and path is used to invoke the handler.\n */\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Mapping {\n    \n    /**\n     * Http method.\n     *\n     * @return Http method\n     */\n    String method();\n    \n    /**\n     * Path pattern of this handler. Starts with '/'.\n     * Such as <code>/app/{jobName}/enable</code>.\n     *\n     * @return Path pattern\n     */\n    String path() default \"\";\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/annotation/Param.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Specify name and source of the parameter.\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.PARAMETER)\npublic @interface Param {\n    \n    /**\n     * Parameter name.\n     *\n     * @return Parameter name\n     */\n    String name();\n    \n    /**\n     * Source of parameter.\n     *\n     * @return Source of parameter\n     */\n    ParamSource source();\n    \n    /**\n     * If the parameter is required.\n     *\n     * @return Requirement\n     */\n    boolean required() default true;\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/annotation/ParamSource.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.annotation;\n\n/**\n * Sources of parameter.\n *\n * @see org.apache.shardingsphere.elasticjob.restful.annotation.Param\n */\npublic enum ParamSource {\n    /**\n     * Request path.\n     */\n    PATH,\n    \n    /**\n     * Query parameters.\n     */\n    QUERY,\n    \n    /**\n     * HTTP headers.\n     */\n    HEADER,\n    \n    /**\n     * HTTP request body.\n     */\n    BODY,\n    \n    /**\n     * Unknown source.\n     */\n    UNKNOWN\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/annotation/RequestBody.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotate the parameter which is from HTTP request body.\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.PARAMETER)\npublic @interface RequestBody {\n    \n    /**\n     * If request body is required.\n     *\n     * @return Required\n     */\n    boolean required() default true;\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/annotation/Returning.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.annotation;\n\nimport org.apache.shardingsphere.elasticjob.restful.Http;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Annotate on handler method to declare HTTP status code and content type of HTTP response.\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.METHOD)\npublic @interface Returning {\n    \n    /**\n     * HTTP status code to return after handling.\n     *\n     * @return Http status code\n     */\n    int code() default 200;\n    \n    /**\n     * HTTP content type of response.\n     *\n     * @return HTTP content type\n     */\n    String contentType() default Http.DEFAULT_CONTENT_TYPE;\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/deserializer/RequestBodyDeserializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.deserializer;\n\n/**\n * Deserializer for deserializing request body with specific MIME type.\n */\npublic interface RequestBodyDeserializer {\n    \n    /**\n     * Specify which type would be deserialized by this deserializer.\n     *\n     * @return MIME type\n     */\n    String mimeType();\n    \n    /**\n     * Deserialize request body to an object.\n     *\n     * @param targetType       Target type\n     * @param requestBodyBytes Request body bytes\n     * @param <T>              Target type\n     * @return Deserialized object\n     */\n    <T> T deserialize(Class<T> targetType, byte[] requestBodyBytes);\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/deserializer/RequestBodyDeserializerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.deserializer;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.factory.DeserializerFactory;\nimport org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;\n\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Request body deserializer factory.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class RequestBodyDeserializerFactory {\n    \n    private static final Map<String, RequestBodyDeserializer> REQUEST_BODY_DESERIALIZERS = new ConcurrentHashMap<>();\n    \n    private static final Map<String, DeserializerFactory> DEFAULT_REQUEST_BODY_DESERIALIZER_FACTORIES = new ConcurrentHashMap<>();\n    \n    private static final RequestBodyDeserializer MISSING_DESERIALIZER = new RequestBodyDeserializer() {\n        \n        @Override\n        public String mimeType() {\n            throw new UnsupportedOperationException();\n        }\n        \n        @Override\n        public <T> T deserialize(final Class<T> targetType, final byte[] requestBodyBytes) {\n            throw new UnsupportedOperationException();\n        }\n    };\n    \n    static {\n        for (RequestBodyDeserializer deserializer : ShardingSphereServiceLoader.getServiceInstances(RequestBodyDeserializer.class)) {\n            REQUEST_BODY_DESERIALIZERS.put(deserializer.mimeType(), deserializer);\n        }\n        for (DeserializerFactory factory : ShardingSphereServiceLoader.getServiceInstances(DeserializerFactory.class)) {\n            DEFAULT_REQUEST_BODY_DESERIALIZER_FACTORIES.put(factory.mimeType(), factory);\n        }\n    }\n    \n    /**\n     * Get deserializer for specific HTTP content type.\n     *\n     * <p>\n     * This method will look for a deserializer instance of specific MIME type.\n     * If deserializer not found, this method would look for deserializer factory by MIME type.\n     * If it is still not found, the MIME type would be marked as <code>MISSING_DESERIALIZER</code>.\n     * </p>\n     *\n     * <p>\n     * Some default deserializer will be provided by {@link DeserializerFactory},\n     * so developers can implement {@link RequestBodyDeserializer} and register it by SPI to override default deserializer.\n     * </p>\n     *\n     * @param contentType HTTP content type\n     * @return Deserializer\n     */\n    public static RequestBodyDeserializer getRequestBodyDeserializer(final String contentType) {\n        RequestBodyDeserializer result = REQUEST_BODY_DESERIALIZERS.get(contentType);\n        if (null == result) {\n            synchronized (RequestBodyDeserializerFactory.class) {\n                if (null == REQUEST_BODY_DESERIALIZERS.get(contentType)) {\n                    instantiateRequestBodyDeserializerFromFactories(contentType);\n                }\n                result = REQUEST_BODY_DESERIALIZERS.get(contentType);\n            }\n        }\n        if (MISSING_DESERIALIZER == result) {\n            throw new RequestBodyDeserializerNotFoundException(contentType);\n        }\n        return result;\n    }\n    \n    private static void instantiateRequestBodyDeserializerFromFactories(final String contentType) {\n        RequestBodyDeserializer deserializer;\n        DeserializerFactory factory = DEFAULT_REQUEST_BODY_DESERIALIZER_FACTORIES.get(contentType);\n        deserializer = Optional.ofNullable(factory).map(DeserializerFactory::createDeserializer).orElse(MISSING_DESERIALIZER);\n        REQUEST_BODY_DESERIALIZERS.put(contentType, deserializer);\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/deserializer/RequestBodyDeserializerNotFoundException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.deserializer;\n\nimport java.text.MessageFormat;\n\n/**\n * {@link RequestBodyDeserializer} not found for specific MIME type.\n */\npublic final class RequestBodyDeserializerNotFoundException extends RuntimeException {\n    \n    private static final long serialVersionUID = 828418332240856770L;\n    \n    public RequestBodyDeserializerNotFoundException(final String mimeType) {\n        super(MessageFormat.format(\"RequestBodySerializer not found for [{0}]\", mimeType));\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/deserializer/factory/DeserializerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.deserializer.factory;\n\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\n\n/**\n * Deserializer factory.\n *\n * @see RequestBodyDeserializer\n * @see org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializerFactory\n */\n@SingletonSPI\npublic interface DeserializerFactory {\n    \n    /**\n     * Specify which type would be deserialized by the deserializer created by this factory.\n     *\n     * @return MIME type\n     */\n    String mimeType();\n    \n    /**\n     * Deserializer factory method.\n     *\n     * @return Instance of deserializer\n     */\n    RequestBodyDeserializer createDeserializer();\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/deserializer/factory/impl/DefaultJsonRequestBodyDeserializerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.deserializer.factory.impl;\n\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.factory.DeserializerFactory;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.impl.DefaultJsonRequestBodyDeserializer;\n\npublic final class DefaultJsonRequestBodyDeserializerFactory implements DeserializerFactory {\n    \n    @Override\n    public String mimeType() {\n        return HttpHeaderValues.APPLICATION_JSON.toString();\n    }\n    \n    @Override\n    public RequestBodyDeserializer createDeserializer() {\n        return new DefaultJsonRequestBodyDeserializer();\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/deserializer/factory/impl/DefaultTextPlainRequestBodyDeserializerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.deserializer.factory.impl;\n\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.factory.DeserializerFactory;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.impl.DefaultTextPlainRequestBodyDeserializer;\n\npublic final class DefaultTextPlainRequestBodyDeserializerFactory implements DeserializerFactory {\n    \n    @Override\n    public String mimeType() {\n        return HttpHeaderValues.TEXT_PLAIN.toString();\n    }\n    \n    @Override\n    public RequestBodyDeserializer createDeserializer() {\n        return new DefaultTextPlainRequestBodyDeserializer();\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/deserializer/impl/DefaultJsonRequestBodyDeserializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.deserializer.impl;\n\nimport com.google.gson.Gson;\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.json.GsonFactory;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;\n\nimport java.nio.charset.StandardCharsets;\n\n/**\n * Deserializer for <code>application/json</code>.\n */\npublic final class DefaultJsonRequestBodyDeserializer implements RequestBodyDeserializer {\n    \n    private final Gson gson = GsonFactory.getGson();\n    \n    @Override\n    public String mimeType() {\n        return HttpHeaderValues.APPLICATION_JSON.toString();\n    }\n    \n    @Override\n    public <T> T deserialize(final Class<T> targetType, final byte[] requestBodyBytes) {\n        if (0 == requestBodyBytes.length) {\n            return null;\n        }\n        return gson.fromJson(new String(requestBodyBytes, StandardCharsets.UTF_8), targetType);\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/deserializer/impl/DefaultTextPlainRequestBodyDeserializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.deserializer.impl;\n\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\n\nimport java.nio.charset.StandardCharsets;\nimport java.text.MessageFormat;\n\n/**\n * Default deserializer for <code>text/plain</code>.\n */\n@SingletonSPI\npublic final class DefaultTextPlainRequestBodyDeserializer implements RequestBodyDeserializer {\n    \n    @Override\n    public String mimeType() {\n        return HttpHeaderValues.TEXT_PLAIN.toString();\n    }\n    \n    @Override\n    public <T> T deserialize(final Class<T> targetType, final byte[] requestBodyBytes) {\n        if (byte[].class.equals(targetType)) {\n            return (T) requestBodyBytes;\n        }\n        if (String.class.isAssignableFrom(targetType)) {\n            return (T) new String(requestBodyBytes, StandardCharsets.UTF_8);\n        }\n        throw new UnsupportedOperationException(MessageFormat.format(\"Cannot deserialize [{0}] into [{1}]\", mimeType(), targetType.getName()));\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/filter/DefaultFilterChain.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.filter;\n\nimport com.google.common.base.Preconditions;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.ReferenceCountUtil;\nimport org.apache.shardingsphere.elasticjob.restful.Filter;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandleContext;\n\nimport java.util.List;\n\n/**\n * Default filter chain.\n */\npublic final class DefaultFilterChain implements FilterChain {\n    \n    private final Filter[] filters;\n    \n    private final ChannelHandlerContext ctx;\n    \n    private final HandleContext<?> handleContext;\n    \n    private int current;\n    \n    private boolean passedThrough;\n    \n    private boolean replied;\n    \n    public DefaultFilterChain(final List<Filter> filterInstances, final ChannelHandlerContext ctx, final HandleContext<?> handleContext) {\n        filters = filterInstances.toArray(new Filter[0]);\n        this.ctx = ctx;\n        this.handleContext = handleContext;\n    }\n    \n    @Override\n    public void next(final FullHttpRequest httpRequest) {\n        Preconditions.checkState(!passedThrough && !replied, \"FilterChain has already finished.\");\n        if (current < filters.length) {\n            filters[current++].doFilter(httpRequest, handleContext.getHttpResponse(), this);\n            if (!passedThrough && !replied) {\n                doResponse();\n            }\n            return;\n        }\n        passedThrough = true;\n        ctx.fireChannelRead(handleContext);\n    }\n    \n    private void doResponse() {\n        try {\n            ctx.writeAndFlush(handleContext.getHttpResponse());\n            replied = true;\n        } finally {\n            ReferenceCountUtil.release(handleContext.getHttpRequest());\n        }\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/filter/FilterChain.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.filter;\n\nimport io.netty.handler.codec.http.FullHttpRequest;\n\n/**\n * Filter chain for {@link org.apache.shardingsphere.elasticjob.restful.Filter}.\n */\npublic interface FilterChain {\n    \n    /**\n     * Next filter.\n     *\n     * @param httpRequest HTTP request\n     */\n    void next(FullHttpRequest httpRequest);\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/handler/ExceptionHandleResult.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.handler;\n\nimport lombok.Builder;\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\n\n@Builder\n@Getter\npublic final class ExceptionHandleResult {\n    \n    private final Object result;\n    \n    @Builder.Default\n    private final int statusCode = 500;\n    \n    @Builder.Default\n    private final String contentType = Http.DEFAULT_CONTENT_TYPE;\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/handler/ExceptionHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.handler;\n\n/**\n * If an exception was thrown, {@link org.apache.shardingsphere.elasticjob.restful.pipeline.ExceptionHandling}\n * will search a proper handler to handle it.\n *\n * @param <E> Type of Exception\n */\npublic interface ExceptionHandler<E extends Throwable> {\n    \n    /**\n     * Handler for specific Exception.\n     *\n     * @param ex Exception\n     * @return Handle result\n     */\n    ExceptionHandleResult handleException(E ex);\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/handler/HandleContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.handler;\n\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.restful.mapping.MappingContext;\n\n/**\n * HandleContext will hold a instance of HTTP request, {@link MappingContext} and arguments for handle method invoking.\n *\n * @param <T> Type of MappingContext\n */\n@RequiredArgsConstructor\n@Getter\n@Setter\npublic final class HandleContext<T> {\n    \n    private final FullHttpRequest httpRequest;\n    \n    private final FullHttpResponse httpResponse;\n    \n    private MappingContext<T> mappingContext;\n    \n    private Object[] args = new Object[0];\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/handler/Handler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.handler;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.ParamSource;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Param;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.RequestBody;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Returning;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Parameter;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * Handle holds a handle method and an instance for method invoking.\n * Describes parameters requirements of handle method.\n */\npublic final class Handler {\n    \n    private final Object instance;\n    \n    private final Method handleMethod;\n    \n    @Getter\n    private final List<HandlerParameter> handlerParameters;\n    \n    /**\n     * HTTP status code to return.\n     */\n    @Getter\n    private final int httpStatusCode;\n    \n    /**\n     * Content type to producing.\n     */\n    @Getter\n    private final String producing;\n    \n    public Handler(final Object instance, final Method handleMethod) {\n        this.instance = instance;\n        this.handleMethod = handleMethod;\n        this.handlerParameters = parseHandleMethodParameter();\n        this.httpStatusCode = parseReturning();\n        this.producing = parseProducing();\n    }\n    \n    /**\n     * Execute handle method with required arguments.\n     *\n     * @param args Required arguments\n     * @return Method invoke result\n     * @throws InvocationTargetException Wraps exception thrown by invoked method\n     * @throws IllegalAccessException    Handle method is not accessible\n     */\n    public Object execute(final Object... args) throws InvocationTargetException, IllegalAccessException {\n        return handleMethod.invoke(instance, args);\n    }\n    \n    private List<HandlerParameter> parseHandleMethodParameter() {\n        List<HandlerParameter> params = new LinkedList<>();\n        Parameter[] parameters = handleMethod.getParameters();\n        for (int i = 0; i < parameters.length; i++) {\n            Parameter parameter = parameters[i];\n            Param annotation = parameter.getAnnotation(Param.class);\n            HandlerParameter handlerParameter;\n            RequestBody requestBody;\n            if (null != annotation) {\n                handlerParameter = new HandlerParameter(i, parameter.getType(), annotation.source(), annotation.name(), annotation.required());\n            } else if (null != (requestBody = parameter.getAnnotation(RequestBody.class))) {\n                handlerParameter = new HandlerParameter(i, parameter.getType(), ParamSource.BODY, parameter.getName(), requestBody.required());\n            } else {\n                handlerParameter = new HandlerParameter(i, parameter.getType(), ParamSource.UNKNOWN, parameter.getName(), false);\n            }\n            params.add(handlerParameter);\n        }\n        return Collections.unmodifiableList(params);\n    }\n    \n    private int parseReturning() {\n        Returning returning = handleMethod.getAnnotation(Returning.class);\n        return Optional.ofNullable(returning).map(Returning::code).orElse(200);\n    }\n    \n    private String parseProducing() {\n        Returning returning = handleMethod.getAnnotation(Returning.class);\n        return Optional.ofNullable(returning).map(Returning::contentType).orElse(Http.DEFAULT_CONTENT_TYPE);\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/handler/HandlerMappingRegistry.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.handler;\n\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpRequest;\nimport org.apache.shardingsphere.elasticjob.restful.mapping.MappingContext;\nimport org.apache.shardingsphere.elasticjob.restful.mapping.RegexUrlPatternMap;\nimport org.apache.shardingsphere.elasticjob.restful.mapping.UrlPatternMap;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\n\n/**\n * HandlerMappingRegistry stores mappings of handlers.\n * Search a proper {@link MappingContext} by HTTP method and request URI.\n */\npublic final class HandlerMappingRegistry {\n    \n    private final Map<HttpMethod, UrlPatternMap<Handler>> mappings = new HashMap<>();\n    \n    /**\n     * Get a MappingContext with Handler for the request.\n     *\n     * @param httpRequest HTTP request\n     * @return A MappingContext if matched, return null if mismatched.\n     */\n    public Optional<MappingContext<Handler>> getMappingContext(final HttpRequest httpRequest) {\n        String uriWithoutQuery = httpRequest.uri().split(\"\\\\?\")[0];\n        return Optional.ofNullable(mappings.get(httpRequest.method())).map(urlPatternMap -> urlPatternMap.match(uriWithoutQuery));\n    }\n    \n    /**\n     * Add a Handler for a path pattern.\n     *\n     * @param method HTTP method\n     * @param pathPattern path pattern\n     * @param handler handler\n     */\n    public void addMapping(final HttpMethod method, final String pathPattern, final Handler handler) {\n        UrlPatternMap<Handler> urlPatternMap = mappings.computeIfAbsent(method, httpMethod -> new RegexUrlPatternMap<>());\n        urlPatternMap.put(pathPattern, handler);\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/handler/HandlerNotFoundException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.handler;\n\nimport java.text.MessageFormat;\n\npublic final class HandlerNotFoundException extends RuntimeException {\n    \n    private static final long serialVersionUID = 7316145545440327554L;\n    \n    public HandlerNotFoundException(final String path) {\n        super(MessageFormat.format(\"No handler found for [{0}].\", path));\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/handler/HandlerParameter.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.handler;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.ParamSource;\n\n/**\n * Describe parameters of a handle method.\n */\n@RequiredArgsConstructor\n@Getter\npublic final class HandlerParameter {\n    \n    private final int index;\n    \n    private final Class<?> type;\n    \n    private final ParamSource paramSource;\n    \n    private final String name;\n    \n    private final boolean required;\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/handler/impl/DefaultExceptionHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.handler.impl;\n\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.handler.ExceptionHandleResult;\nimport org.apache.shardingsphere.elasticjob.restful.handler.ExceptionHandler;\n\n/**\n * A default handler for handling {@link Throwable}.\n */\npublic final class DefaultExceptionHandler implements ExceptionHandler<Throwable> {\n    \n    @Override\n    public ExceptionHandleResult handleException(final Throwable ex) {\n        return ExceptionHandleResult.builder()\n                .statusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code())\n                .contentType(Http.DEFAULT_CONTENT_TYPE)\n                .result(ex.getLocalizedMessage())\n                .build();\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/handler/impl/DefaultHandlerNotFoundExceptionHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.handler.impl;\n\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.handler.ExceptionHandleResult;\nimport org.apache.shardingsphere.elasticjob.restful.handler.ExceptionHandler;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandlerNotFoundException;\n\n/**\n * A default handler for {@link HandlerNotFoundException}.\n */\npublic final class DefaultHandlerNotFoundExceptionHandler implements ExceptionHandler<HandlerNotFoundException> {\n    \n    @Override\n    public ExceptionHandleResult handleException(final HandlerNotFoundException ex) {\n        return ExceptionHandleResult.builder()\n                .statusCode(HttpResponseStatus.NOT_FOUND.code())\n                .result(ex.getLocalizedMessage())\n                .contentType(Http.DEFAULT_CONTENT_TYPE)\n                .build();\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/mapping/AmbiguousPathPatternException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.mapping;\n\n/**\n * A path matched more than one path patterns and failed to determine which pattern is more proper.\n */\npublic final class AmbiguousPathPatternException extends RuntimeException {\n    \n    private static final long serialVersionUID = -7109813692538597236L;\n    \n    public AmbiguousPathPatternException(final String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/mapping/DefaultMappingContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.mapping;\n\nimport lombok.RequiredArgsConstructor;\n\n/**\n * Default mapping context.\n *\n * @param <T> Type of payload\n */\n@RequiredArgsConstructor\npublic final class DefaultMappingContext<T> implements MappingContext<T> {\n    \n    private final String pattern;\n    \n    private final T payload;\n    \n    @Override\n    public String pattern() {\n        return pattern;\n    }\n    \n    @Override\n    public T payload() {\n        return payload;\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/mapping/MappingContext.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.mapping;\n\n/**\n * Mapping context will hold a path pattern and a payload.\n *\n * @param <T> payload type\n */\npublic interface MappingContext<T> {\n    \n    /**\n     * The path pattern of mapping context.\n     *\n     * @return path pattern\n     */\n    String pattern();\n    \n    /**\n     * Payload of mapping context.\n     *\n     * @return payload\n     */\n    T payload();\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/mapping/PathMatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.mapping;\n\nimport java.util.Map;\n\n/**\n * PathMatcher is a supporting tool for HTTP request dispatching.\n * <p>\n * Used by {@link UrlPatternMap}, {@link org.apache.shardingsphere.elasticjob.restful.pipeline.HandlerParameterDecoder}\n * for template variables extracting, path pattern validating, pattern matching.\n * </p>\n *\n * @see RegexPathMatcher\n */\npublic interface PathMatcher {\n    \n    /**\n     * Capture actual values of placeholder.\n     * The format of Path pattern likes <code>/app/{jobName}/{status}</code>.\n     *\n     * @param pathPattern path pattern contains templates\n     * @param path actual path\n     * @return map from template name to actual value\n     */\n    Map<String, String> captureVariables(String pathPattern, String path);\n    \n    /**\n     * Check if the path pattern matches the given path.\n     *\n     * @param pathPattern path pattern\n     * @param path the path to check\n     * @return true if matched, or else false\n     */\n    boolean matches(String pathPattern, String path);\n    \n    /**\n     * Check if the given string is a valid path pattern.\n     *\n     * @param pathPattern path pattern to check\n     * @return true if valid, or else false\n     */\n    boolean isValidPathPattern(String pathPattern);\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/mapping/RegexPathMatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.mapping;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Implemented {@link PathMatcher} by regular expression.\n */\npublic final class RegexPathMatcher implements PathMatcher {\n    \n    private static final String PATH_SEPARATOR = \"/\";\n    \n    private static final Pattern PATH_PATTERN = Pattern.compile(\"^/(([^/{}]+|\\\\{[^/{}]+})(/([^/{}]+|\\\\{[^/{}]+}))*/?)?$\");\n    \n    private static final Pattern TEMPLATE_PATTERN = Pattern.compile(\"\\\\{(?<template>[^/]+)}\");\n    \n    private static final String TEMPLATE_REGEX = \"(?<${template}>[^/]+)\";\n    \n    private final Map<String, Pattern> patternCache = new ConcurrentHashMap<>();\n    \n    @Override\n    public Map<String, String> captureVariables(final String pathPattern, final String path) {\n        Pattern compiled = getCompiledPattern(pathPattern);\n        String pathWithoutQuery = trimUriQuery(path);\n        Matcher matcher = compiled.matcher(pathWithoutQuery);\n        if (!matcher.matches() || 0 == matcher.groupCount()) {\n            return Collections.emptyMap();\n        }\n        Map<String, String> variables = new LinkedHashMap<>();\n        for (String variableName : extractTemplateNames(pathPattern)) {\n            variables.put(variableName, matcher.group(variableName));\n        }\n        return Collections.unmodifiableMap(variables);\n    }\n    \n    @Override\n    public boolean matches(final String pathPattern, final String path) {\n        return getCompiledPattern(pathPattern).matcher(trimUriQuery(path)).matches();\n    }\n    \n    @Override\n    public boolean isValidPathPattern(final String pathPattern) {\n        return PATH_PATTERN.matcher(pathPattern).matches();\n    }\n    \n    private Pattern getCompiledPattern(final String pathPattern) {\n        String regexPattern = convertToRegexPattern(pathPattern);\n        patternCache.computeIfAbsent(regexPattern, Pattern::compile);\n        return patternCache.get(regexPattern);\n    }\n    \n    private String convertToRegexPattern(final String pathPattern) {\n        return TEMPLATE_PATTERN.matcher(pathPattern).replaceAll(TEMPLATE_REGEX);\n    }\n    \n    private List<String> extractTemplateNames(final String pathPattern) {\n        String[] pathFragments = pathPattern.split(PATH_SEPARATOR);\n        List<String> result = new ArrayList<>();\n        for (String fragment : pathFragments) {\n            int start = fragment.indexOf('{');\n            int end = fragment.lastIndexOf('}');\n            if (-1 != start && -1 != end) {\n                result.add(fragment.substring(start + 1, end));\n            }\n        }\n        return result;\n    }\n    \n    private String trimUriQuery(final String uri) {\n        int index = uri.indexOf('?');\n        if (-1 != index) {\n            return uri.substring(0, index);\n        }\n        return uri;\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/mapping/RegexUrlPatternMap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.mapping;\n\nimport com.google.common.base.Preconditions;\n\nimport java.text.MessageFormat;\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.regex.Pattern;\n\n/**\n * Implemented {@link UrlPatternMap} by regular expression.\n *\n * @param <V> Type of payload\n */\npublic final class RegexUrlPatternMap<V> implements UrlPatternMap<V> {\n    \n    private static final String PATH_SEPARATOR = \"/\";\n    \n    private static final Pattern TEMPLATE_PATTERN = Pattern.compile(\"(?<=/)\\\\{(?<template>[^/]+)}\");\n    \n    private final Map<String, MappingContext<V>> map = new LinkedHashMap<>();\n    \n    private final PathMatcher pathMatcher = new RegexPathMatcher();\n    \n    @Override\n    public void put(final String pathPattern, final V value) {\n        Objects.requireNonNull(pathPattern, \"Path pattern must be not null.\");\n        Preconditions.checkArgument(pathMatcher.isValidPathPattern(pathPattern), \"Path pattern [%s] invalid.\", pathPattern);\n        String unified = unifyPattern(pathPattern);\n        MappingContext<V> mappingContext = new DefaultMappingContext<>(pathPattern, value);\n        if (map.containsKey(unified)) {\n            throw new IllegalArgumentException(String.format(\"Duplicate pattern [%s]\", unified));\n        }\n        map.put(unified, mappingContext);\n    }\n    \n    @Override\n    public MappingContext<V> match(final String path) {\n        List<MappingContext<V>> hits = new ArrayList<>();\n        for (Map.Entry<String, MappingContext<V>> entry : map.entrySet()) {\n            final String pattern = entry.getKey();\n            if (pattern.equals(path)) {\n                return entry.getValue();\n            }\n            if (pathMatcher.matches(pattern, path)) {\n                hits.add(entry.getValue());\n            }\n        }\n        if (hits.isEmpty()) {\n            return null;\n        }\n        if (1 < hits.size()) {\n            hits.sort(new MappingComparator().reversed());\n        }\n        return hits.get(0);\n    }\n    \n    private String unifyPattern(final String pattern) {\n        return TEMPLATE_PATTERN.matcher(pattern).replaceAll(\"[^/]+\");\n    }\n    \n    static class MappingComparator implements Comparator<MappingContext<?>> {\n        \n        @Override\n        public int compare(final MappingContext<?> o1, final MappingContext<?> o2) {\n            String[] s1 = o1.pattern().split(PATH_SEPARATOR);\n            String[] s2 = o2.pattern().split(PATH_SEPARATOR);\n            int len = Math.min(s1.length, s2.length);\n            for (int i = 0; i < len; i++) {\n                if (isTemplate(s1[i]) && !isTemplate(s2[i])) {\n                    return -1;\n                }\n                if (!isTemplate(s1[i]) && isTemplate(s2[i])) {\n                    return 1;\n                }\n            }\n            throw new AmbiguousPathPatternException(MessageFormat.format(\"Ambiguous path pattern: [{0}], [{1}].\", o1.pattern(), o2.pattern()));\n        }\n        \n        private static boolean isTemplate(final String fragment) {\n            return fragment.startsWith(\"{\") && fragment.endsWith(\"}\");\n        }\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/mapping/UrlPatternMap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.mapping;\n\n/**\n * URL pattern map is used for path pattern storage and path matching.\n * {@link MappingContext} is an object holding path pattern and payload.\n *\n * @param <V> Type of payload\n */\npublic interface UrlPatternMap<V> {\n    \n    /**\n     * Add a path pattern and value to URL pattern map.\n     *\n     * @param pathPattern path pattern\n     * @param value payload of the path pattern\n     */\n    void put(String pathPattern, V value);\n    \n    /**\n     * Find a proper mapping context for current path.\n     *\n     * @param path a path to match.\n     * @return a mapping context if the path matched a pattern, return null if mismatched.\n     */\n    MappingContext<V> match(String path);\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/pipeline/ContextInitializationInboundHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.codec.http.DefaultFullHttpResponse;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.handler.codec.http.HttpUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandleContext;\nimport org.apache.shardingsphere.elasticjob.restful.handler.Handler;\n\n/**\n * Create an instance of {@link FullHttpResponse} and initialize {@link HandleContext}.\n */\n@Sharable\n@Slf4j\npublic final class ContextInitializationInboundHandler extends ChannelInboundHandlerAdapter {\n    \n    @Override\n    public void channelRead(final ChannelHandlerContext ctx, final Object msg) {\n        log.debug(\"{}\", msg);\n        FullHttpRequest httpRequest = (FullHttpRequest) msg;\n        FullHttpResponse httpResponse = new DefaultFullHttpResponse(httpRequest.protocolVersion(), HttpResponseStatus.NOT_FOUND, ctx.alloc().buffer());\n        HttpUtil.setContentLength(httpResponse, httpResponse.content().readableBytes());\n        ctx.fireChannelRead(new HandleContext<Handler>(httpRequest, httpResponse));\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/pipeline/ExceptionHandling.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.codec.http.DefaultFullHttpResponse;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport io.netty.handler.codec.http.HttpHeaderNames;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.handler.codec.http.HttpUtil;\nimport io.netty.handler.codec.http.HttpVersion;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.restful.handler.ExceptionHandleResult;\nimport org.apache.shardingsphere.elasticjob.restful.handler.ExceptionHandler;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandlerNotFoundException;\nimport org.apache.shardingsphere.elasticjob.restful.handler.impl.DefaultExceptionHandler;\nimport org.apache.shardingsphere.elasticjob.restful.handler.impl.DefaultHandlerNotFoundExceptionHandler;\nimport org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializer;\nimport org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializerFactory;\n\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Catch exceptions and look for exception handler.\n */\n@Slf4j\n@Sharable\npublic final class ExceptionHandling extends ChannelInboundHandlerAdapter {\n    \n    private static final DefaultExceptionHandler DEFAULT_EXCEPTION_HANDLER = new DefaultExceptionHandler();\n    \n    private final Map<Class<? extends Throwable>, ExceptionHandler<? extends Throwable>> exceptionHandlers = new ConcurrentHashMap<>();\n    \n    public ExceptionHandling(final Map<Class<? extends Throwable>, ExceptionHandler<? extends Throwable>> exceptionHandlers) {\n        initDefaultExceptionHandlers();\n        addCustomExceptionHandlers(exceptionHandlers);\n    }\n    \n    private void initDefaultExceptionHandlers() {\n        exceptionHandlers.put(HandlerNotFoundException.class, new DefaultHandlerNotFoundExceptionHandler());\n    }\n    \n    private void addCustomExceptionHandlers(final Map<Class<? extends Throwable>, ExceptionHandler<? extends Throwable>> exceptionHandlers) {\n        for (Map.Entry<Class<? extends Throwable>, ExceptionHandler<? extends Throwable>> entry : exceptionHandlers.entrySet()) {\n            Class<? extends Throwable> exceptionType = entry.getKey();\n            ExceptionHandler<? extends Throwable> oldHandler = this.exceptionHandlers.put(exceptionType, entry.getValue());\n            if (null != oldHandler) {\n                log.info(\"Overriding ExceptionHandler for [{}]\", exceptionType.getName());\n            }\n        }\n    }\n    \n    @Override\n    public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {\n        ExceptionHandler<Throwable> exceptionHandler = searchExceptionHandler(cause);\n        ExceptionHandleResult handleResult = exceptionHandler.handleException(cause);\n        String mimeType = HttpUtil.getMimeType(handleResult.getContentType()).toString();\n        ResponseBodySerializer serializer = ResponseBodySerializerFactory.getResponseBodySerializer(mimeType);\n        byte[] body = serializer.serialize(handleResult.getResult());\n        FullHttpResponse response = createHttpResponse(handleResult.getStatusCode(), handleResult.getContentType(), body);\n        ctx.writeAndFlush(response);\n    }\n    \n    private FullHttpResponse createHttpResponse(final int statusCode, final String contentType, final byte[] body) {\n        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(statusCode), Unpooled.copiedBuffer(body));\n        response.headers().set(HttpHeaderNames.CONTENT_TYPE, contentType);\n        HttpUtil.setContentLength(response, body.length);\n        return response;\n    }\n    \n    private <T extends Throwable> ExceptionHandler<T> searchExceptionHandler(final Throwable cause) {\n        Class<? extends Throwable> exceptionType = cause.getClass();\n        ExceptionHandler<? extends Throwable> exceptionHandler = exceptionHandlers.get(exceptionType);\n        if (null == exceptionHandler) {\n            for (Map.Entry<Class<? extends Throwable>, ExceptionHandler<? extends Throwable>> entry : exceptionHandlers.entrySet()) {\n                Class<? extends Throwable> clazz = entry.getKey();\n                ExceptionHandler<? extends Throwable> handler = entry.getValue();\n                if (clazz.isAssignableFrom(exceptionType)) {\n                    exceptionHandler = handler;\n                    break;\n                }\n            }\n        }\n        if (null == exceptionHandler) {\n            exceptionHandler = DEFAULT_EXCEPTION_HANDLER;\n        }\n        return (ExceptionHandler<T>) exceptionHandler;\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/pipeline/FilterChainInboundHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.restful.Filter;\nimport org.apache.shardingsphere.elasticjob.restful.filter.DefaultFilterChain;\nimport org.apache.shardingsphere.elasticjob.restful.filter.FilterChain;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandleContext;\nimport org.apache.shardingsphere.elasticjob.restful.handler.Handler;\n\nimport java.util.List;\n\n/**\n * Filter chain inbound handler.\n */\n@Slf4j\n@Sharable\n@RequiredArgsConstructor\npublic final class FilterChainInboundHandler extends ChannelInboundHandlerAdapter {\n    \n    private final List<Filter> filterInstances;\n    \n    @SuppressWarnings({\"NullableProblems\", \"unchecked\"})\n    @Override\n    public void channelRead(final ChannelHandlerContext ctx, final Object msg) {\n        if (filterInstances.isEmpty()) {\n            ctx.fireChannelRead(msg);\n            return;\n        }\n        HandleContext<Handler> handleContext = (HandleContext<Handler>) msg;\n        FilterChain filterChain = new DefaultFilterChain(filterInstances, ctx, handleContext);\n        filterChain.next(handleContext.getHttpRequest());\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/pipeline/HandleMethodExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport io.netty.handler.codec.http.HttpHeaderNames;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.handler.codec.http.HttpUtil;\nimport io.netty.util.ReferenceCountUtil;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandleContext;\nimport org.apache.shardingsphere.elasticjob.restful.handler.Handler;\nimport org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializer;\nimport org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializerFactory;\n\nimport java.lang.reflect.InvocationTargetException;\n\n/**\n * The handler which actually executes handle method and creates HTTP response for responding.\n * If an exception occurred when executing handle method, this handler would pass it to Handler named {@link ExceptionHandling}.\n */\n@Sharable\npublic final class HandleMethodExecutor extends ChannelInboundHandlerAdapter {\n    \n    @SuppressWarnings({\"unchecked\", \"NullableProblems\"})\n    @Override\n    public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {\n        HandleContext<Handler> handleContext = (HandleContext<Handler>) msg;\n        try {\n            Handler handler = handleContext.getMappingContext().payload();\n            Object[] args = handleContext.getArgs();\n            Object handleResult = handler.execute(args);\n            FullHttpResponse httpResponse = handleContext.getHttpResponse();\n            if (null != handleResult) {\n                String mimeType = HttpUtil.getMimeType(handler.getProducing()).toString();\n                ResponseBodySerializer serializer = ResponseBodySerializerFactory.getResponseBodySerializer(mimeType);\n                byte[] bodyBytes = serializer.serialize(handleResult);\n                populateHttpResponse(httpResponse, handler.getProducing(), bodyBytes, handler.getHttpStatusCode());\n            } else {\n                populateHttpResponse(httpResponse, handler.getProducing(), new byte[0], handler.getHttpStatusCode());\n            }\n            ctx.writeAndFlush(httpResponse);\n        } finally {\n            ReferenceCountUtil.release(handleContext.getHttpRequest());\n        }\n    }\n    \n    private void populateHttpResponse(final FullHttpResponse httpResponse, final String producingContentType, final byte[] bodyBytes, final int statusCode) {\n        HttpResponseStatus httpResponseStatus = HttpResponseStatus.valueOf(statusCode);\n        httpResponse.setStatus(httpResponseStatus);\n        httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, producingContentType);\n        httpResponse.content().writeBytes(bodyBytes);\n        HttpUtil.setContentLength(httpResponse, httpResponse.content().readableBytes());\n        HttpUtil.setKeepAlive(httpResponse, true);\n    }\n    \n    @Override\n    public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {\n        if (cause instanceof InvocationTargetException) {\n            ctx.fireExceptionCaught(cause.getCause());\n        } else {\n            ctx.fireExceptionCaught(cause);\n        }\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/pipeline/HandlerParameterDecoder.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport com.google.common.base.Preconditions;\nimport io.netty.buffer.ByteBufUtil;\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpUtil;\nimport io.netty.handler.codec.http.QueryStringDecoder;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializer;\nimport org.apache.shardingsphere.elasticjob.restful.deserializer.RequestBodyDeserializerFactory;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandleContext;\nimport org.apache.shardingsphere.elasticjob.restful.handler.Handler;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandlerParameter;\nimport org.apache.shardingsphere.elasticjob.restful.mapping.MappingContext;\nimport org.apache.shardingsphere.elasticjob.restful.mapping.PathMatcher;\nimport org.apache.shardingsphere.elasticjob.restful.mapping.RegexPathMatcher;\nimport org.apache.shardingsphere.elasticjob.restful.wrapper.QueryParameterMap;\n\nimport java.text.MessageFormat;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n/**\n * This handler is used for preparing parameters before executing handle method.\n * It prepares arguments declared by {@link org.apache.shardingsphere.elasticjob.restful.annotation.Param}\n * and {@link org.apache.shardingsphere.elasticjob.restful.annotation.RequestBody}, and deserializes arguments to declared type.\n */\n@Slf4j\n@Sharable\npublic final class HandlerParameterDecoder extends ChannelInboundHandlerAdapter {\n    \n    private final PathMatcher pathMatcher = new RegexPathMatcher();\n    \n    @SuppressWarnings({\"unchecked\", \"NullableProblems\"})\n    @Override\n    public void channelRead(final ChannelHandlerContext ctx, final Object msg) {\n        HandleContext<Handler> handleContext = (HandleContext<Handler>) msg;\n        FullHttpRequest httpRequest = handleContext.getHttpRequest();\n        MappingContext<Handler> mappingContext = handleContext.getMappingContext();\n        Object[] arguments = prepareArguments(httpRequest, mappingContext);\n        handleContext.setArgs(arguments);\n        ctx.fireChannelRead(handleContext);\n    }\n    \n    private Object[] prepareArguments(final FullHttpRequest httpRequest, final MappingContext<Handler> mappingContext) {\n        Handler handler = mappingContext.payload();\n        List<HandlerParameter> handlerParameters = handler.getHandlerParameters();\n        Map<String, List<String>> queryParameters = parseQuery(httpRequest.uri());\n        Map<String, String> templateVariables = pathMatcher.captureVariables(mappingContext.pattern(), httpRequest.uri());\n        Object[] result = new Object[handlerParameters.size()];\n        boolean requestBodyAlreadyParsed = false;\n        for (int i = 0; i < handlerParameters.size(); i++) {\n            HandlerParameter handlerParameter = handlerParameters.get(i);\n            Object parsedValue = null;\n            String parameterName = handlerParameter.getName();\n            Class<?> targetType = handlerParameter.getType();\n            boolean nullable = !handlerParameter.isRequired();\n            switch (handlerParameter.getParamSource()) {\n                case PATH:\n                    String rawPathValue = templateVariables.get(parameterName);\n                    Object parsedPathValue = deserializeBuiltInType(targetType, rawPathValue);\n                    Preconditions.checkArgument(nullable || null != parsedPathValue, \"Missing path variable [%s].\", parameterName);\n                    parsedValue = parsedPathValue;\n                    break;\n                case QUERY:\n                    List<String> rawQueryValues = queryParameters.get(parameterName);\n                    Object parsedQueryValue = deserializeQueryParameter(targetType, rawQueryValues);\n                    Preconditions.checkArgument(nullable || null != parsedQueryValue, \"Missing query parameter [%s].\", parameterName);\n                    parsedValue = parsedQueryValue;\n                    break;\n                case HEADER:\n                    String rawHeaderValue = httpRequest.headers().get(parameterName);\n                    Object parsedHeaderValue = deserializeBuiltInType(targetType, rawHeaderValue);\n                    Preconditions.checkArgument(nullable || null != parsedHeaderValue, \"Missing header value [%s].\", parameterName);\n                    parsedValue = parsedHeaderValue;\n                    break;\n                case BODY:\n                    Preconditions.checkState(!requestBodyAlreadyParsed, \"@RequestBody duplicated on handle method.\");\n                    byte[] bytes = ByteBufUtil.getBytes(httpRequest.content());\n                    String mimeType = Optional.ofNullable(HttpUtil.getMimeType(httpRequest))\n                            .orElseGet(() -> HttpUtil.getMimeType(Http.DEFAULT_CONTENT_TYPE)).toString();\n                    RequestBodyDeserializer deserializer = RequestBodyDeserializerFactory.getRequestBodyDeserializer(mimeType);\n                    Object parsedBodyValue = deserializer.deserialize(targetType, bytes);\n                    parsedValue = parsedBodyValue;\n                    Preconditions.checkArgument(nullable || null != parsedBodyValue, \"Missing request body\");\n                    requestBodyAlreadyParsed = true;\n                    break;\n                case UNKNOWN:\n                    if (QueryParameterMap.class.isAssignableFrom(targetType)) {\n                        parsedValue = new QueryParameterMap(queryParameters);\n                    } else {\n                        log.warn(\"Unknown source argument [{}] on index [{}].\", parameterName, handlerParameter.getIndex());\n                    }\n                    break;\n                default:\n            }\n            result[i] = parsedValue;\n        }\n        return result;\n    }\n    \n    private Map<String, List<String>> parseQuery(final String uri) {\n        QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri);\n        return queryStringDecoder.parameters();\n    }\n    \n    private Object deserializeQueryParameter(final Class<?> targetType, final List<String> queryValues) {\n        if (null == queryValues || queryValues.isEmpty()) {\n            return null;\n        }\n        if (1 == queryValues.size()) {\n            return deserializeBuiltInType(targetType, queryValues.get(0));\n        }\n        throw new UnsupportedOperationException(\"Multi value query doesn't support yet.\");\n    }\n    \n    private Object deserializeBuiltInType(final Class<?> targetType, final String value) {\n        Preconditions.checkArgument(!value.isEmpty(), \"Cannot deserialize empty value.\");\n        if (String.class.equals(targetType)) {\n            return value;\n        }\n        if (Boolean.class.equals(targetType) || boolean.class.equals(targetType)) {\n            return Boolean.parseBoolean(value);\n        }\n        if (Character.class.equals(targetType) || char.class.equals(targetType)) {\n            Preconditions.checkArgument(1 >= value.length(), MessageFormat.format(\"Cannot set value [{0}] into a char.\", value));\n            return value.charAt(0);\n        }\n        if (Byte.class.equals(targetType) || byte.class.equals(targetType)) {\n            return Byte.parseByte(value);\n        }\n        if (Short.class.equals(targetType) || short.class.equals(targetType)) {\n            return Short.parseShort(value);\n        }\n        if (Integer.class.equals(targetType) || int.class.equals(targetType)) {\n            return Integer.parseInt(value);\n        }\n        if (Long.class.equals(targetType) || long.class.equals(targetType)) {\n            return Long.parseLong(value);\n        }\n        if (Float.class.equals(targetType) || float.class.equals(targetType)) {\n            return Float.parseFloat(value);\n        }\n        if (Double.class.equals(targetType) || double.class.equals(targetType)) {\n            return Double.parseDouble(value);\n        }\n        throw new IllegalArgumentException(MessageFormat.format(\"Cannot deserialize path variable [{0}] into [{1}]\", value, targetType.getName()));\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/pipeline/HttpRequestDispatcher.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.util.ReferenceCountUtil;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulController;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.ContextPath;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Mapping;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandleContext;\nimport org.apache.shardingsphere.elasticjob.restful.handler.Handler;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandlerMappingRegistry;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandlerNotFoundException;\nimport org.apache.shardingsphere.elasticjob.restful.mapping.MappingContext;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * If a HTTP request reached, HTTP request dispatcher would lookup a proper Handler for the request.\n * Assemble a {@link HandleContext} with HTTP request and {@link MappingContext}, then pass it to the next in-bound handler.\n */\n@Sharable\npublic final class HttpRequestDispatcher extends ChannelInboundHandlerAdapter {\n    \n    private static final String TRAILING_SLASH = \"/\";\n    \n    private final HandlerMappingRegistry mappingRegistry = new HandlerMappingRegistry();\n    \n    private final boolean trailingSlashSensitive;\n    \n    public HttpRequestDispatcher(final List<RestfulController> restfulControllers, final boolean trailingSlashSensitive) {\n        this.trailingSlashSensitive = trailingSlashSensitive;\n        initMappingRegistry(restfulControllers);\n    }\n    \n    @SuppressWarnings({\"unchecked\", \"NullableProblems\"})\n    @Override\n    public void channelRead(final ChannelHandlerContext ctx, final Object msg) {\n        HandleContext<Handler> handleContext = (HandleContext<Handler>) msg;\n        FullHttpRequest request = handleContext.getHttpRequest();\n        if (!trailingSlashSensitive) {\n            request.setUri(appendTrailingSlashIfAbsent(request.uri()));\n        }\n        Optional<MappingContext<Handler>> mappingContext = mappingRegistry.getMappingContext(request);\n        if (mappingContext.isPresent()) {\n            handleContext.setMappingContext(mappingContext.get());\n            ctx.fireChannelRead(handleContext);\n        } else {\n            ReferenceCountUtil.release(request);\n            throw new HandlerNotFoundException(request.uri());\n        }\n    }\n    \n    private void initMappingRegistry(final List<RestfulController> restfulControllers) {\n        for (RestfulController restfulController : restfulControllers) {\n            Class<? extends RestfulController> controllerClass = restfulController.getClass();\n            String contextPath = Optional.ofNullable(controllerClass.getAnnotation(ContextPath.class)).map(ContextPath::value).orElse(\"\");\n            for (Method method : controllerClass.getMethods()) {\n                Mapping mapping = method.getAnnotation(Mapping.class);\n                if (null == mapping) {\n                    continue;\n                }\n                HttpMethod httpMethod = HttpMethod.valueOf(mapping.method());\n                String path = mapping.path();\n                String fullPathPattern = resolveFullPath(contextPath, path);\n                if (!trailingSlashSensitive) {\n                    fullPathPattern = appendTrailingSlashIfAbsent(fullPathPattern);\n                }\n                mappingRegistry.addMapping(httpMethod, fullPathPattern, new Handler(restfulController, method));\n            }\n        }\n    }\n    \n    private String resolveFullPath(final String contextPath, final String pattern) {\n        return Optional.ofNullable(contextPath).orElse(\"\") + pattern;\n    }\n    \n    private String appendTrailingSlashIfAbsent(final String uri) {\n        String[] split = uri.split(\"\\\\?\");\n        if (1 == split.length) {\n            return uri.endsWith(TRAILING_SLASH) ? uri : uri + TRAILING_SLASH;\n        }\n        String path = split[0];\n        return path.endsWith(TRAILING_SLASH) ? uri : path + TRAILING_SLASH + \"?\" + split[1];\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/pipeline/RestfulServiceChannelInitializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport io.netty.handler.codec.http.HttpServerCodec;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulServiceConfiguration;\n\n/**\n * Initialize channel pipeline.\n */\npublic final class RestfulServiceChannelInitializer extends ChannelInitializer<Channel> {\n    \n    private final ContextInitializationInboundHandler contextInitializationInboundHandler;\n    \n    private final FilterChainInboundHandler filterChainInboundHandler;\n    \n    private final HttpRequestDispatcher httpRequestDispatcher;\n    \n    private final HandlerParameterDecoder handlerParameterDecoder;\n    \n    private final HandleMethodExecutor handleMethodExecutor;\n    \n    private final ExceptionHandling exceptionHandling;\n    \n    public RestfulServiceChannelInitializer(final NettyRestfulServiceConfiguration config) {\n        contextInitializationInboundHandler = new ContextInitializationInboundHandler();\n        filterChainInboundHandler = new FilterChainInboundHandler(config.getFilterInstances());\n        httpRequestDispatcher = new HttpRequestDispatcher(config.getControllerInstances(), config.isTrailingSlashSensitive());\n        handlerParameterDecoder = new HandlerParameterDecoder();\n        handleMethodExecutor = new HandleMethodExecutor();\n        exceptionHandling = new ExceptionHandling(config.getExceptionHandlers());\n    }\n    \n    @Override\n    protected void initChannel(final Channel channel) {\n        ChannelPipeline pipeline = channel.pipeline();\n        pipeline.addLast(\"codec\", new HttpServerCodec());\n        pipeline.addLast(\"aggregator\", new HttpObjectAggregator(1024 * 1024));\n        pipeline.addLast(\"contextInitialization\", contextInitializationInboundHandler);\n        pipeline.addLast(\"filterChain\", filterChainInboundHandler);\n        pipeline.addLast(\"dispatcher\", httpRequestDispatcher);\n        pipeline.addLast(\"handlerParameterDecoder\", handlerParameterDecoder);\n        pipeline.addLast(\"handleMethodExecutor\", handleMethodExecutor);\n        pipeline.addLast(\"exceptionHandling\", exceptionHandling);\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/serializer/ResponseBodySerializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.serializer;\n\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\n\n/**\n * Serializer for serializing response body with specific MIME type.\n */\n@SingletonSPI\npublic interface ResponseBodySerializer {\n    \n    /**\n     * Specify which type would be serialized by this serializer.\n     *\n     * @return MIME type\n     */\n    String mimeType();\n    \n    /**\n     * Serialize object to bytes.\n     *\n     * @param responseBody object to be serialized\n     * @return bytes\n     */\n    byte[] serialize(Object responseBody);\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/serializer/ResponseBodySerializerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.serializer;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.restful.serializer.factory.SerializerFactory;\nimport org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;\n\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * Response body serializer factory.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class ResponseBodySerializerFactory {\n    \n    private static final Map<String, ResponseBodySerializer> RESPONSE_BODY_SERIALIZERS = new ConcurrentHashMap<>();\n    \n    private static final Map<String, SerializerFactory> RESPONSE_BODY_SERIALIZER_FACTORIES = new ConcurrentHashMap<>();\n    \n    private static final ResponseBodySerializer MISSING_SERIALIZER = new ResponseBodySerializer() {\n        \n        @Override\n        public String mimeType() {\n            throw new UnsupportedOperationException();\n        }\n        \n        @Override\n        public byte[] serialize(final Object responseBody) {\n            throw new UnsupportedOperationException();\n        }\n    };\n    \n    static {\n        for (ResponseBodySerializer serializer : ShardingSphereServiceLoader.getServiceInstances(ResponseBodySerializer.class)) {\n            RESPONSE_BODY_SERIALIZERS.put(serializer.mimeType(), serializer);\n        }\n        for (SerializerFactory factory : ShardingSphereServiceLoader.getServiceInstances(SerializerFactory.class)) {\n            RESPONSE_BODY_SERIALIZER_FACTORIES.put(factory.mimeType(), factory);\n        }\n    }\n    \n    /**\n     * Get serializer for specific HTTP content type.\n     *\n     * <p>\n     * This method will look for a serializer instance of specific MIME type.\n     * If serializer not found, this method would look for serializer factory by MIME type.\n     * If it is still not found, the MIME type would be marked as <code>MISSING_SERIALIZER</code>.\n     * </p>\n     *\n     * <p>\n     * Some default serializer will be provided by {@link SerializerFactory},\n     * so developers can implement {@link ResponseBodySerializer} and register it by SPI to override default serializer.\n     * </p>\n     *\n     * @param contentType HTTP content type\n     * @return serializer\n     */\n    public static ResponseBodySerializer getResponseBodySerializer(final String contentType) {\n        ResponseBodySerializer result = RESPONSE_BODY_SERIALIZERS.get(contentType);\n        if (null == result) {\n            synchronized (ResponseBodySerializerFactory.class) {\n                if (null == RESPONSE_BODY_SERIALIZERS.get(contentType)) {\n                    instantiateResponseBodySerializerFromFactories(contentType);\n                }\n                result = RESPONSE_BODY_SERIALIZERS.get(contentType);\n            }\n        }\n        if (MISSING_SERIALIZER == result) {\n            throw new ResponseBodySerializerNotFoundException(contentType);\n        }\n        return result;\n    }\n    \n    private static void instantiateResponseBodySerializerFromFactories(final String contentType) {\n        ResponseBodySerializer serializer;\n        SerializerFactory factory = RESPONSE_BODY_SERIALIZER_FACTORIES.get(contentType);\n        serializer = Optional.ofNullable(factory).map(SerializerFactory::createSerializer).orElse(MISSING_SERIALIZER);\n        RESPONSE_BODY_SERIALIZERS.put(contentType, serializer);\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/serializer/ResponseBodySerializerNotFoundException.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.serializer;\n\nimport java.text.MessageFormat;\n\n/**\n * {@link ResponseBodySerializer} not found for specific MIME type.\n */\npublic final class ResponseBodySerializerNotFoundException extends RuntimeException {\n    \n    private static final long serialVersionUID = 3201288074956273247L;\n    \n    public ResponseBodySerializerNotFoundException(final String mimeType) {\n        super(MessageFormat.format(\"ResponseBodySerializer not found for [{0}]\", mimeType));\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/serializer/factory/SerializerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.serializer.factory;\n\nimport org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializer;\nimport org.apache.shardingsphere.infra.spi.annotation.SingletonSPI;\n\n/**\n * Serializer factory.\n *\n * @see ResponseBodySerializer\n * @see org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializerFactory\n */\n@SingletonSPI\npublic interface SerializerFactory {\n    \n    /**\n     * Specify which type would be serialized by the serializer created by this factory.\n     *\n     * @return MIME type\n     */\n    String mimeType();\n    \n    /**\n     * Serializer factory method.\n     *\n     * @return instance of serializer\n     */\n    ResponseBodySerializer createSerializer();\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/serializer/factory/impl/DefaultJsonResponseBodySerializerFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.serializer.factory.impl;\n\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializer;\nimport org.apache.shardingsphere.elasticjob.restful.serializer.factory.SerializerFactory;\nimport org.apache.shardingsphere.elasticjob.restful.serializer.impl.DefaultJsonResponseBodySerializer;\n\n/**\n * Factory for {@link DefaultJsonResponseBodySerializer}.\n */\npublic final class DefaultJsonResponseBodySerializerFactory implements SerializerFactory {\n    \n    @Override\n    public String mimeType() {\n        return HttpHeaderValues.APPLICATION_JSON.toString();\n    }\n    \n    @Override\n    public ResponseBodySerializer createSerializer() {\n        return new DefaultJsonResponseBodySerializer();\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/serializer/impl/DefaultJsonResponseBodySerializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.serializer.impl;\n\nimport com.google.gson.Gson;\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.json.GsonFactory;\nimport org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializer;\n\nimport java.nio.charset.StandardCharsets;\n\n/**\n * Default serializer for <code>application/json</code>.\n */\npublic final class DefaultJsonResponseBodySerializer implements ResponseBodySerializer {\n    \n    private final Gson gson = GsonFactory.getGson();\n    \n    @Override\n    public String mimeType() {\n        return HttpHeaderValues.APPLICATION_JSON.toString();\n    }\n    \n    @Override\n    public byte[] serialize(final Object responseBody) {\n        if (responseBody instanceof String) {\n            return ((String) responseBody).getBytes(StandardCharsets.UTF_8);\n        }\n        return gson.toJson(responseBody).getBytes(StandardCharsets.UTF_8);\n    }\n}\n"
  },
  {
    "path": "restful/src/main/java/org/apache/shardingsphere/elasticjob/restful/wrapper/QueryParameterMap.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.wrapper;\n\nimport java.util.AbstractMap;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\n/**\n * Wrap a multi-value map. Helps handle method receiving all query parameters.\n */\npublic final class QueryParameterMap extends AbstractMap<String, List<String>> {\n    \n    private final Map<String, List<String>> queryMap;\n    \n    public QueryParameterMap() {\n        queryMap = new LinkedHashMap<>();\n    }\n    \n    public QueryParameterMap(final Map<String, List<String>> map) {\n        queryMap = new LinkedHashMap<>(map);\n    }\n    \n    /**\n     * Get values by parameter name.\n     *\n     * @param parameterName parameter name\n     * @return values\n     */\n    public List<String> get(final String parameterName) {\n        return queryMap.get(parameterName);\n    }\n    \n    /**\n     * Get the first from values.\n     *\n     * @param parameterName parameter name\n     * @return first value\n     */\n    public String getFirst(final String parameterName) {\n        String firstValue = null;\n        List<String> values = queryMap.get(parameterName);\n        if (values != null && !values.isEmpty()) {\n            firstValue = values.get(0);\n        }\n        return firstValue;\n    }\n    \n    @Override\n    public boolean isEmpty() {\n        return queryMap.isEmpty();\n    }\n    \n    @Override\n    public Set<Entry<String, List<String>>> entrySet() {\n        return queryMap.entrySet();\n    }\n    \n    /**\n     * Add value.\n     *\n     * @param parameterName parameter name\n     * @param value value\n     */\n    public void add(final String parameterName, final String value) {\n        List<String> values = queryMap.get(parameterName);\n        if (null == values) {\n            values = new LinkedList<>();\n        }\n        values.add(value);\n        put(parameterName, values);\n    }\n    \n    @Override\n    public List<String> put(final String parameterName, final List<String> value) {\n        return queryMap.put(parameterName, value);\n    }\n    \n    /**\n     * Convert to a single value map, abandon values except the first of each parameter.\n     *\n     * @return single value map\n     */\n    public Map<String, String> toSingleValueMap() {\n        return queryMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().get(0)));\n    }\n}\n"
  },
  {
    "path": "restful/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.restful.deserializer.factory.DeserializerFactory",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.restful.deserializer.factory.impl.DefaultJsonRequestBodyDeserializerFactory\norg.apache.shardingsphere.elasticjob.restful.deserializer.factory.impl.DefaultTextPlainRequestBodyDeserializerFactory\n"
  },
  {
    "path": "restful/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.restful.serializer.factory.SerializerFactory",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.restful.serializer.factory.impl.DefaultJsonResponseBodySerializerFactory\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/RegexPathMatcherTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful;\n\nimport org.apache.shardingsphere.elasticjob.restful.mapping.PathMatcher;\nimport org.apache.shardingsphere.elasticjob.restful.mapping.RegexPathMatcher;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Map;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass RegexPathMatcherTest {\n    \n    @Test\n    void assertCaptureTemplate() {\n        PathMatcher pathMatcher = new RegexPathMatcher();\n        Map<String, String> variables = pathMatcher.captureVariables(\"/app/{jobName}/disable/{until}/done\", \"/app/myJob/disable/20201231/done?name=some_name&value=some_value\");\n        assertFalse(variables.isEmpty());\n        assertThat(variables.size(), is(2));\n        assertThat(variables.get(\"jobName\"), is(\"myJob\"));\n        assertThat(variables.get(\"until\"), is(\"20201231\"));\n        assertNull(variables.get(\"app\"));\n    }\n    \n    @Test\n    void assertCapturePatternWithoutTemplate() {\n        PathMatcher pathMatcher = new RegexPathMatcher();\n        Map<String, String> variables = pathMatcher.captureVariables(\"/app\", \"/app\");\n        assertTrue(variables.isEmpty());\n    }\n    \n    @Test\n    void assertPathMatch() {\n        PathMatcher pathMatcher = new RegexPathMatcher();\n        assertTrue(pathMatcher.matches(\"/app/{jobName}\", \"/app/myJob\"));\n    }\n    \n    @Test\n    void assertValidatePathPattern() {\n        PathMatcher pathMatcher = new RegexPathMatcher();\n        assertTrue(pathMatcher.isValidPathPattern(\"/\"));\n        assertTrue(pathMatcher.isValidPathPattern(\"/app\"));\n        assertTrue(pathMatcher.isValidPathPattern(\"/app/job\"));\n        assertTrue(pathMatcher.isValidPathPattern(\"/app/job/\"));\n        assertTrue(pathMatcher.isValidPathPattern(\"/app/{jobName}\"));\n        assertTrue(pathMatcher.isValidPathPattern(\"/{appName}/{jobName}/status\"));\n        assertFalse(pathMatcher.isValidPathPattern(\"/app/jobName}\"));\n        assertFalse(pathMatcher.isValidPathPattern(\"/app/{jobName\"));\n        assertFalse(pathMatcher.isValidPathPattern(\"/app/{job}Name\"));\n        assertFalse(pathMatcher.isValidPathPattern(\"/app//jobName\"));\n        assertFalse(pathMatcher.isValidPathPattern(\"//app/jobName\"));\n        assertFalse(pathMatcher.isValidPathPattern(\"app/jobName\"));\n        assertFalse(pathMatcher.isValidPathPattern(\"\"));\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/RegexUrlPatternMapTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful;\n\nimport org.apache.shardingsphere.elasticjob.restful.mapping.MappingContext;\nimport org.apache.shardingsphere.elasticjob.restful.mapping.RegexUrlPatternMap;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass RegexUrlPatternMapTest {\n    \n    @Test\n    void assertRegexUrlPatternMap() {\n        RegexUrlPatternMap<Integer> urlPatternMap = new RegexUrlPatternMap<>();\n        urlPatternMap.put(\"/app/{jobName}\", 1);\n        urlPatternMap.put(\"/app/list\", 2);\n        urlPatternMap.put(\"/app/{jobName}/disable\", 3);\n        urlPatternMap.put(\"/app/{jobName}/enable\", 4);\n        MappingContext<Integer> mappingContext = urlPatternMap.match(\"/app/myJob\");\n        assertNotNull(mappingContext);\n        assertThat(mappingContext.pattern(), is(\"/app/{jobName}\"));\n        assertThat(mappingContext.payload(), is(1));\n        mappingContext = urlPatternMap.match(\"/app/list\");\n        assertNotNull(mappingContext);\n        assertThat(mappingContext.pattern(), is(\"/app/list\"));\n        assertThat(mappingContext.payload(), is(2));\n        mappingContext = urlPatternMap.match(\"/job/list\");\n        assertNull(mappingContext);\n    }\n    \n    @Test\n    void assertAmbiguous() {\n        RegexUrlPatternMap<Integer> urlPatternMap = new RegexUrlPatternMap<>();\n        urlPatternMap.put(\"/foo/{bar}/{fooName}/status\", 10);\n        urlPatternMap.put(\"/foo/{bar}/operate/{metrics}\", 11);\n        MappingContext<Integer> mappingContext = urlPatternMap.match(\"/foo/barValue/operate/status\");\n        assertNotNull(mappingContext);\n        assertThat(mappingContext.pattern(), is(\"/foo/{bar}/operate/{metrics}\"));\n        assertThat(mappingContext.payload(), is(11));\n    }\n    \n    @Test\n    void assertDuplicate() {\n        assertThrows(IllegalArgumentException.class, () -> {\n            RegexUrlPatternMap<Integer> urlPatternMap = new RegexUrlPatternMap<>();\n            urlPatternMap.put(\"/app/{jobName}/enable\", 0);\n            urlPatternMap.put(\"/app/{jobName}\", 1);\n            urlPatternMap.put(\"/app/{appName}\", 2);\n        });\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/controller/IndexController.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.controller;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulController;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Mapping;\n\n@Slf4j\npublic final class IndexController implements RestfulController {\n    \n    /**\n     * A mapping declare path implicit, meaning it mapped index.\n     *\n     * @return a string\n     */\n    @Mapping(method = Http.GET)\n    public String index() {\n        return \"hello, elastic-job\";\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/controller/JobController.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.controller;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.ParamSource;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulController;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.ContextPath;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Mapping;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Param;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.RequestBody;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Returning;\nimport org.apache.shardingsphere.elasticjob.restful.pojo.JobPojo;\n\n@Slf4j\n@ContextPath(\"/job\")\npublic final class JobController implements RestfulController {\n    \n    /**\n     * Pretend to create a job.\n     *\n     * @param group group\n     * @param jobName job name\n     * @param cron job cron\n     * @param description job description\n     * @return result\n     */\n    @Mapping(method = Http.POST, path = \"/{group}/{jobName}\")\n    public JobPojo createJob(@Param(name = \"group\", source = ParamSource.PATH) final String group,\n                             @Param(name = \"jobName\", source = ParamSource.PATH) final String jobName,\n                             @Param(name = \"cron\", source = ParamSource.QUERY) final String cron,\n                             @RequestBody final String description) {\n        JobPojo result = new JobPojo();\n        result.setName(jobName);\n        result.setCron(cron);\n        result.setGroup(group);\n        result.setDescription(description);\n        return result;\n    }\n    \n    /**\n     * Throw an illegal state exception.\n     *\n     * @param message Exception message\n     * @return None\n     */\n    @Mapping(method = Http.GET, path = \"/throw/IllegalState\")\n    public Object throwIllegalStateException(@Param(name = \"Exception-Message\", source = ParamSource.HEADER) final String message) {\n        throw new IllegalStateException(message);\n    }\n    \n    /**\n     * Throw an illegal argument exception.\n     *\n     * @param message exception message\n     * @return none\n     */\n    @Mapping(method = Http.GET, path = \"/throw/IllegalArgument\")\n    public Object throwIllegalArgumentException(@Param(name = \"Exception-Message\", source = ParamSource.HEADER) final String message) {\n        throw new IllegalArgumentException(message);\n    }\n    \n    /**\n     * Return 204.\n     *\n     * @param noop useless\n     * @return none\n     */\n    @Mapping(method = Http.GET, path = \"/code/204\")\n    @Returning(code = 204)\n    public Object return204(final String noop) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/controller/TrailingSlashTestController.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.controller;\n\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulController;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.ContextPath;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Mapping;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Returning;\n\n@ContextPath(\"/trailing\")\npublic final class TrailingSlashTestController implements RestfulController {\n    \n    /**\n     * A mapping without trailing slash.\n     *\n     * @return a string\n     */\n    @Mapping(method = Http.GET, path = \"/slash\")\n    @Returning(contentType = \"text/plain; charset=utf-8\")\n    public String withoutTrailingSlash() {\n        return \"without trailing slash\";\n    }\n    \n    /**\n     * A mapping with trailing slash.\n     *\n     * @return a string\n     */\n    @Mapping(method = Http.GET, path = \"/slash/\")\n    @Returning(contentType = \"text/plain; charset=utf-8\")\n    public String withTrailingSlash() {\n        return \"with trailing slash\";\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/deserializer/RequestBodyDeserializerFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.deserializer;\n\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass RequestBodyDeserializerFactoryTest {\n    \n    @Test\n    void assertGetJsonDefaultDeserializer() {\n        RequestBodyDeserializer deserializer = RequestBodyDeserializerFactory.getRequestBodyDeserializer(HttpHeaderValues.APPLICATION_JSON.toString());\n        assertNotNull(deserializer);\n    }\n    \n    @Test\n    void assertDeserializerNotFound() {\n        assertThrows(RequestBodyDeserializerNotFoundException.class, () -> RequestBodyDeserializerFactory.getRequestBodyDeserializer(\"Unknown\"));\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/filter/DefaultFilterChainTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.filter;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport lombok.SneakyThrows;\nimport org.apache.shardingsphere.elasticjob.restful.Filter;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandleContext;\nimport org.apache.shardingsphere.elasticjob.restful.handler.Handler;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.lang.reflect.Field;\nimport java.util.Arrays;\nimport java.util.Collections;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.verify;\n\n@ExtendWith(MockitoExtension.class)\nclass DefaultFilterChainTest {\n    \n    @Mock\n    private ChannelHandlerContext ctx;\n    \n    @Mock\n    private FullHttpRequest httpRequest;\n    \n    @Mock\n    private FullHttpResponse httpResponse;\n    \n    private HandleContext<Handler> handleContext;\n    \n    @BeforeEach\n    void setUp() {\n        handleContext = new HandleContext<>(httpRequest, httpResponse);\n    }\n    \n    @Test\n    void assertNoFilter() {\n        DefaultFilterChain filterChain = new DefaultFilterChain(Collections.emptyList(), ctx, handleContext);\n        filterChain.next(httpRequest);\n        verify(ctx, never()).writeAndFlush(httpResponse);\n        verify(ctx).fireChannelRead(handleContext);\n        assertTrue(isPassedThrough(filterChain));\n        assertFalse(isReplied(filterChain));\n    }\n    \n    @Test\n    void assertWithSingleFilterPassed() {\n        Filter passableFilter = spy(new PassableFilter());\n        DefaultFilterChain filterChain = new DefaultFilterChain(Collections.singletonList(passableFilter), ctx, handleContext);\n        filterChain.next(httpRequest);\n        verify(passableFilter).doFilter(httpRequest, httpResponse, filterChain);\n        verify(ctx).fireChannelRead(handleContext);\n        verify(ctx, never()).writeAndFlush(httpResponse);\n        assertTrue(isPassedThrough(filterChain));\n        assertFalse(isReplied(filterChain));\n    }\n    \n    @Test\n    void assertWithSingleFilterDoResponse() {\n        Filter impassableFilter = mock(Filter.class);\n        DefaultFilterChain filterChain = new DefaultFilterChain(Collections.singletonList(impassableFilter), ctx, handleContext);\n        filterChain.next(httpRequest);\n        verify(impassableFilter).doFilter(httpRequest, httpResponse, filterChain);\n        verify(ctx, never()).fireChannelRead(any(HandleContext.class));\n        verify(ctx).writeAndFlush(httpResponse);\n        assertTrue(isReplied(filterChain));\n        assertFalse(isPassedThrough(filterChain));\n    }\n    \n    @Test\n    void assertWithThreeFiltersPassed() {\n        Filter firstFilter = spy(new PassableFilter());\n        Filter secondFilter = spy(new PassableFilter());\n        Filter thirdFilter = spy(new PassableFilter());\n        DefaultFilterChain filterChain = new DefaultFilterChain(Arrays.asList(firstFilter, secondFilter, thirdFilter), ctx, handleContext);\n        filterChain.next(httpRequest);\n        verify(firstFilter).doFilter(httpRequest, httpResponse, filterChain);\n        verify(secondFilter).doFilter(httpRequest, httpResponse, filterChain);\n        verify(thirdFilter).doFilter(httpRequest, httpResponse, filterChain);\n        assertTrue(isPassedThrough(filterChain));\n        assertFalse(isReplied(filterChain));\n        verify(ctx).fireChannelRead(handleContext);\n        verify(ctx, never()).writeAndFlush(any(FullHttpResponse.class));\n    }\n    \n    @Test\n    void assertWithThreeFiltersDoResponseByTheSecond() {\n        Filter firstFilter = spy(new PassableFilter());\n        Filter secondFilter = mock(Filter.class);\n        Filter thirdFilter = spy(new PassableFilter());\n        DefaultFilterChain filterChain = new DefaultFilterChain(Arrays.asList(firstFilter, secondFilter, thirdFilter), ctx, handleContext);\n        filterChain.next(httpRequest);\n        verify(firstFilter).doFilter(httpRequest, httpResponse, filterChain);\n        verify(secondFilter).doFilter(httpRequest, httpResponse, filterChain);\n        assertFalse(isPassedThrough(filterChain));\n        assertTrue(isReplied(filterChain));\n        verify(thirdFilter, never()).doFilter(httpRequest, httpResponse, filterChain);\n        verify(ctx, never()).fireChannelRead(any(HandleContext.class));\n        verify(ctx).writeAndFlush(httpResponse);\n    }\n    \n    @Test\n    void assertInvokeFinishedFilterChainWithoutFilter() {\n        assertThrows(IllegalStateException.class, () -> {\n            DefaultFilterChain filterChain = new DefaultFilterChain(Collections.emptyList(), ctx, handleContext);\n            filterChain.next(httpRequest);\n            filterChain.next(httpRequest);\n        });\n    }\n    \n    @Test\n    void assertInvokePassedThroughFilterChainWithTwoFilters() {\n        assertThrows(IllegalStateException.class, () -> {\n            Filter firstFilter = spy(new PassableFilter());\n            Filter secondFilter = spy(new PassableFilter());\n            DefaultFilterChain filterChain = new DefaultFilterChain(Arrays.asList(firstFilter, secondFilter), ctx, handleContext);\n            filterChain.next(httpRequest);\n            verify(firstFilter).doFilter(httpRequest, httpResponse, filterChain);\n            verify(secondFilter).doFilter(httpRequest, httpResponse, filterChain);\n            verify(ctx).fireChannelRead(handleContext);\n            filterChain.next(httpRequest);\n        });\n    }\n    \n    private boolean isPassedThrough(final DefaultFilterChain filterChain) {\n        return getBoolean(filterChain, \"passedThrough\");\n    }\n    \n    private boolean isReplied(final DefaultFilterChain filterChain) {\n        return getBoolean(filterChain, \"replied\");\n    }\n    \n    @SneakyThrows\n    private boolean getBoolean(final DefaultFilterChain filterChain, final String fieldName) {\n        Field field = DefaultFilterChain.class.getDeclaredField(fieldName);\n        field.setAccessible(true);\n        return (boolean) field.get(filterChain);\n    }\n    \n    private static class PassableFilter implements Filter {\n        \n        @Override\n        public void doFilter(final FullHttpRequest httpRequest, final FullHttpResponse httpResponse, final FilterChain filterChain) {\n            filterChain.next(httpRequest);\n        }\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/handler/CustomIllegalStateExceptionHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.handler;\n\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.pojo.ResultDto;\n\npublic final class CustomIllegalStateExceptionHandler implements ExceptionHandler<IllegalStateException> {\n    \n    @Override\n    public ExceptionHandleResult handleException(final IllegalStateException ex) {\n        return ExceptionHandleResult.builder()\n                .statusCode(403)\n                .contentType(Http.DEFAULT_CONTENT_TYPE)\n                .result(ResultDto.builder().code(1).data(ex.getLocalizedMessage()).build())\n                .build();\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/pipeline/FilterChainInboundHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport io.netty.channel.embedded.EmbeddedChannel;\nimport org.apache.shardingsphere.elasticjob.restful.Filter;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandleContext;\nimport org.apache.shardingsphere.elasticjob.restful.handler.Handler;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\n\nimport java.util.List;\n\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@ExtendWith(MockitoExtension.class)\nclass FilterChainInboundHandlerTest {\n    \n    @Mock\n    private List<Filter> filterInstances;\n    \n    @Mock\n    private HandleContext<Handler> handleContext;\n    \n    private EmbeddedChannel channel;\n    \n    @BeforeEach\n    void setUp() {\n        channel = new EmbeddedChannel(new FilterChainInboundHandler(filterInstances));\n    }\n    \n    @Test\n    void assertNoFilter() {\n        when(filterInstances.isEmpty()).thenReturn(true);\n        channel.writeOneInbound(handleContext);\n        verify(handleContext, never()).getHttpRequest();\n    }\n    \n    @Test\n    void assertFilterExists() {\n        when(filterInstances.isEmpty()).thenReturn(false);\n        channel.writeOneInbound(handleContext);\n        verify(handleContext, atLeastOnce()).getHttpRequest();\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/pipeline/HandlerParameterDecoderTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.ByteBufUtil;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.embedded.EmbeddedChannel;\nimport io.netty.handler.codec.http.DefaultFullHttpRequest;\nimport io.netty.handler.codec.http.DefaultHttpHeaders;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport io.netty.handler.codec.http.HttpHeaders;\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpVersion;\nimport io.netty.handler.codec.http.QueryStringEncoder;\nimport org.apache.shardingsphere.elasticjob.restful.Http;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulController;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Mapping;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.Param;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.ParamSource;\nimport org.apache.shardingsphere.elasticjob.restful.annotation.RequestBody;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Collections;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass HandlerParameterDecoderTest {\n    \n    private EmbeddedChannel channel;\n    \n    @BeforeEach\n    void setUp() {\n        ContextInitializationInboundHandler contextInitializationInboundHandler = new ContextInitializationInboundHandler();\n        HttpRequestDispatcher httpRequestDispatcher = new HttpRequestDispatcher(Collections.singletonList(new DecoderTestController()), false);\n        HandlerParameterDecoder handlerParameterDecoder = new HandlerParameterDecoder();\n        HandleMethodExecutor handleMethodExecutor = new HandleMethodExecutor();\n        channel = new EmbeddedChannel(contextInitializationInboundHandler, httpRequestDispatcher, handlerParameterDecoder, handleMethodExecutor);\n    }\n    \n    @Test\n    void assertDecodeParameters() {\n        QueryStringEncoder queryStringEncoder = new QueryStringEncoder(\"/myApp/C\");\n        queryStringEncoder.addParam(\"cron\", \"0 * * * * ?\");\n        queryStringEncoder.addParam(\"integer\", \"30\");\n        queryStringEncoder.addParam(\"bool\", \"true\");\n        queryStringEncoder.addParam(\"long\", \"3000\");\n        queryStringEncoder.addParam(\"double\", \"23.33\");\n        String uri = queryStringEncoder.toString();\n        ByteBuf body = Unpooled.wrappedBuffer(\"BODY\".getBytes());\n        HttpHeaders headers = new DefaultHttpHeaders();\n        headers.set(\"Message\", \"some_message\");\n        FullHttpRequest httpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri, body, headers, headers);\n        channel.writeInbound(httpRequest);\n        FullHttpResponse httpResponse = channel.readOutbound();\n        assertThat(httpResponse.status().code(), is(200));\n        assertThat(new String(ByteBufUtil.getBytes(httpResponse.content())), is(\"ok\"));\n    }\n    \n    public static class DecoderTestController implements RestfulController {\n        \n        /**\n         * A handle method for decode testing.\n         *\n         * @param appName     string from path\n         * @param ch          character from path\n         * @param cron        cron from query\n         * @param message     message from header\n         * @param body        from request body\n         * @param integer     integer from query\n         * @param bool        boolean from query\n         * @param longValue   long from query\n         * @param doubleValue double from query\n         * @return OK\n         */\n        @Mapping(method = Http.GET, path = \"/{appName}/{ch}\")\n        public String handle(\n                             final @Param(source = ParamSource.PATH, name = \"appName\") String appName,\n                             final @Param(source = ParamSource.PATH, name = \"ch\") char ch,\n                             final @Param(source = ParamSource.QUERY, name = \"cron\") String cron,\n                             final @Param(source = ParamSource.HEADER, name = \"Message\") String message,\n                             final @RequestBody String body,\n                             final @Param(source = ParamSource.QUERY, name = \"integer\") int integer,\n                             final @Param(source = ParamSource.QUERY, name = \"bool\") Boolean bool,\n                             final @Param(source = ParamSource.QUERY, name = \"long\") Long longValue,\n                             final @Param(source = ParamSource.QUERY, name = \"double\") double doubleValue) {\n            assertThat(appName, is(\"myApp\"));\n            assertThat(ch, is('C'));\n            assertThat(cron, is(\"0 * * * * ?\"));\n            assertThat(message, is(\"some_message\"));\n            assertThat(body, is(\"BODY\"));\n            assertThat(integer, is(30));\n            assertThat(bool, is(true));\n            assertThat(longValue, is(3000L));\n            assertThat(doubleValue, is(23.33));\n            return \"ok\";\n        }\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/pipeline/HttpClient.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport io.netty.bootstrap.Bootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.nio.NioSocketChannel;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport io.netty.handler.codec.http.HttpClientCodec;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport lombok.SneakyThrows;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class HttpClient {\n    \n    /**\n     * Send a HTTP request and invoke consumer when server response.\n     *\n     * @param host server host\n     * @param port server port\n     * @param request HTTP request\n     * @param consumer HTTP response consumer\n     * @param timeoutSeconds wait for consume\n     */\n    @SneakyThrows(InterruptedException.class)\n    public static void request(final String host, final int port, final FullHttpRequest request, final Consumer<FullHttpResponse> consumer, final Long timeoutSeconds) {\n        CountDownLatch countDownLatch = new CountDownLatch(1);\n        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();\n        Channel channel = new Bootstrap()\n                .group(eventLoopGroup)\n                .channel(NioSocketChannel.class)\n                .remoteAddress(host, port)\n                .handler(new ChannelInitializer<Channel>() {\n                    \n                    @Override\n                    protected void initChannel(final Channel ch) {\n                        ch.pipeline()\n                                .addLast(new HttpClientCodec())\n                                .addLast(new HttpObjectAggregator(1024 * 1024))\n                                .addLast(new SimpleChannelInboundHandler<FullHttpResponse>() {\n                                    \n                                    @Override\n                                    protected void channelRead0(final ChannelHandlerContext ctx, final FullHttpResponse httpResponse) {\n                                        try {\n                                            consumer.accept(httpResponse);\n                                        } finally {\n                                            countDownLatch.countDown();\n                                        }\n                                    }\n                                });\n                    }\n                }).connect()\n                .sync().channel();\n        channel.writeAndFlush(request);\n        countDownLatch.await(timeoutSeconds, TimeUnit.SECONDS);\n        channel.close().sync();\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/pipeline/HttpRequestDispatcherTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport com.google.common.collect.Lists;\nimport io.netty.channel.embedded.EmbeddedChannel;\nimport io.netty.handler.codec.http.DefaultFullHttpRequest;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpVersion;\nimport org.apache.shardingsphere.elasticjob.restful.controller.JobController;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandleContext;\nimport org.apache.shardingsphere.elasticjob.restful.handler.HandlerNotFoundException;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass HttpRequestDispatcherTest {\n    \n    @Test\n    void assertDispatcherHandlerNotFound() {\n        assertThrows(HandlerNotFoundException.class, () -> {\n            EmbeddedChannel channel = new EmbeddedChannel(new HttpRequestDispatcher(Lists.newArrayList(new JobController()), false));\n            FullHttpRequest fullHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, \"/hello/myJob/myCron\");\n            channel.writeInbound(new HandleContext<>(fullHttpRequest, null));\n        });\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/pipeline/NettyRestfulServiceTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport com.google.gson.Gson;\nimport io.netty.buffer.ByteBufUtil;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.DefaultFullHttpRequest;\nimport io.netty.handler.codec.http.HttpHeaderNames;\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpUtil;\nimport io.netty.handler.codec.http.HttpVersion;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulService;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulServiceConfiguration;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulService;\nimport org.apache.shardingsphere.elasticjob.restful.controller.IndexController;\nimport org.apache.shardingsphere.elasticjob.restful.controller.JobController;\nimport org.apache.shardingsphere.elasticjob.restful.handler.CustomIllegalStateExceptionHandler;\nimport org.apache.shardingsphere.elasticjob.restful.pojo.JobPojo;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.Timeout;\n\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLEncoder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertEquals;\n\nclass NettyRestfulServiceTest {\n    \n    private static final long TESTCASE_TIMEOUT = 10000L;\n    \n    private static final String HOST = \"localhost\";\n    \n    private static final int PORT = 18080;\n    \n    private static RestfulService restfulService;\n    \n    @BeforeAll\n    static void init() {\n        NettyRestfulServiceConfiguration config = new NettyRestfulServiceConfiguration(PORT);\n        config.setHost(HOST);\n        config.addControllerInstances(new JobController(), new IndexController());\n        config.addExceptionHandler(IllegalStateException.class, new CustomIllegalStateExceptionHandler());\n        restfulService = new NettyRestfulService(config);\n        restfulService.startup();\n    }\n    \n    @Test\n    @Timeout(value = TESTCASE_TIMEOUT, unit = TimeUnit.MILLISECONDS)\n    void assertRequestWithParameters() throws UnsupportedEncodingException {\n        String cron = \"0 * * * * ?\";\n        String uri = String.format(\"/job/myGroup/myJob?cron=%s\", URLEncoder.encode(cron, \"UTF-8\"));\n        String description = \"Descriptions about this job.\";\n        byte[] body = description.getBytes(StandardCharsets.UTF_8);\n        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uri, Unpooled.wrappedBuffer(body));\n        request.headers().set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN);\n        HttpUtil.setContentLength(request, body.length);\n        HttpClient.request(HOST, PORT, request, httpResponse -> {\n            assertEquals(200, httpResponse.status().code());\n            byte[] bytes = ByteBufUtil.getBytes(httpResponse.content());\n            String json = new String(bytes, StandardCharsets.UTF_8);\n            Gson gson = new Gson();\n            JobPojo jobPojo = gson.fromJson(json, JobPojo.class);\n            assertThat(jobPojo.getCron(), is(cron));\n            assertThat(jobPojo.getGroup(), is(\"myGroup\"));\n            assertThat(jobPojo.getName(), is(\"myJob\"));\n            assertThat(jobPojo.getDescription(), is(description));\n        }, TESTCASE_TIMEOUT);\n    }\n    \n    @Test\n    @Timeout(value = TESTCASE_TIMEOUT, unit = TimeUnit.MILLISECONDS)\n    void assertCustomExceptionHandler() {\n        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, \"/job/throw/IllegalState\");\n        request.headers().set(\"Exception-Message\", \"An illegal state exception message.\");\n        HttpClient.request(HOST, PORT, request, httpResponse -> {\n            // Handle by CustomExceptionHandler\n            assertThat(httpResponse.status().code(), is(403));\n        }, TESTCASE_TIMEOUT);\n    }\n    \n    @Test\n    @Timeout(value = TESTCASE_TIMEOUT, unit = TimeUnit.MILLISECONDS)\n    void assertUsingDefaultExceptionHandler() {\n        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, \"/job/throw/IllegalArgument\");\n        request.headers().set(\"Exception-Message\", \"An illegal argument exception message.\");\n        HttpClient.request(HOST, PORT, request, httpResponse -> {\n            // Handle by DefaultExceptionHandler\n            assertThat(httpResponse.status().code(), is(500));\n        }, TESTCASE_TIMEOUT);\n    }\n    \n    @Test\n    @Timeout(value = TESTCASE_TIMEOUT, unit = TimeUnit.MILLISECONDS)\n    void assertReturnStatusCode() {\n        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, \"/job/code/204\");\n        HttpClient.request(HOST, PORT, request, httpResponse -> assertThat(httpResponse.status().code(), is(204)), TESTCASE_TIMEOUT);\n    }\n    \n    @Test\n    @Timeout(value = TESTCASE_TIMEOUT, unit = TimeUnit.MILLISECONDS)\n    void assertHandlerNotFound() {\n        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, \"/not/found\");\n        HttpClient.request(HOST, PORT, request, httpResponse -> assertThat(httpResponse.status().code(), is(404)), TESTCASE_TIMEOUT);\n    }\n    \n    @Test\n    @Timeout(value = TESTCASE_TIMEOUT, unit = TimeUnit.MILLISECONDS)\n    void assertRequestIndexWithSlash() {\n        DefaultFullHttpRequest requestWithSlash = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, \"/\");\n        HttpClient.request(HOST, PORT, requestWithSlash, httpResponse -> assertThat(httpResponse.status().code(), is(200)), TESTCASE_TIMEOUT);\n    }\n    \n    @Test\n    @Timeout(value = TESTCASE_TIMEOUT, unit = TimeUnit.MILLISECONDS)\n    void assertRequestIndexWithoutSlash() {\n        DefaultFullHttpRequest requestWithoutSlash = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, \"\");\n        HttpClient.request(HOST, PORT, requestWithoutSlash, httpResponse -> assertThat(httpResponse.status().code(), is(200)), TESTCASE_TIMEOUT);\n    }\n    \n    @AfterAll\n    static void tearDown() {\n        if (null != restfulService) {\n            restfulService.shutdown();\n        }\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/pipeline/NettyRestfulServiceTrailingSlashInsensitiveTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulService;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulServiceConfiguration;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulService;\nimport org.apache.shardingsphere.elasticjob.restful.controller.TrailingSlashTestController;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass NettyRestfulServiceTrailingSlashInsensitiveTest {\n    \n    private static final String HOST = \"localhost\";\n    \n    private static final int PORT = 18082;\n    \n    @Test\n    void assertPathDuplicateWhenTrailingSlashInsensitive() {\n        assertThrows(IllegalArgumentException.class, () -> {\n            NettyRestfulServiceConfiguration config = new NettyRestfulServiceConfiguration(PORT);\n            config.setHost(HOST);\n            config.addControllerInstances(new TrailingSlashTestController());\n            RestfulService restfulService = new NettyRestfulService(config);\n            restfulService.startup();\n        });\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/pipeline/NettyRestfulServiceTrailingSlashSensitiveTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pipeline;\n\nimport io.netty.buffer.ByteBufUtil;\nimport io.netty.handler.codec.http.DefaultFullHttpRequest;\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpVersion;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulService;\nimport org.apache.shardingsphere.elasticjob.restful.NettyRestfulServiceConfiguration;\nimport org.apache.shardingsphere.elasticjob.restful.RestfulService;\nimport org.apache.shardingsphere.elasticjob.restful.controller.TrailingSlashTestController;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.Timeout;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass NettyRestfulServiceTrailingSlashSensitiveTest {\n    \n    private static final long TESTCASE_TIMEOUT = 10000L;\n    \n    private static final String HOST = \"localhost\";\n    \n    private static final int PORT = 18081;\n    \n    private static RestfulService restfulService;\n    \n    @BeforeAll\n    static void init() {\n        NettyRestfulServiceConfiguration config = new NettyRestfulServiceConfiguration(PORT);\n        config.setHost(HOST);\n        config.setTrailingSlashSensitive(true);\n        config.addControllerInstances(new TrailingSlashTestController());\n        restfulService = new NettyRestfulService(config);\n        restfulService.startup();\n    }\n    \n    @Test\n    @Timeout(value = TESTCASE_TIMEOUT, unit = TimeUnit.MILLISECONDS)\n    void assertWithoutTrailingSlash() {\n        DefaultFullHttpRequest requestWithSlash = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, \"/trailing/slash\");\n        HttpClient.request(HOST, PORT, requestWithSlash, httpResponse -> {\n            assertThat(httpResponse.status().code(), is(200));\n            byte[] bytes = ByteBufUtil.getBytes(httpResponse.content());\n            String body = new String(bytes, StandardCharsets.UTF_8);\n            assertThat(body, is(\"without trailing slash\"));\n        }, TESTCASE_TIMEOUT);\n    }\n    \n    @Test\n    @Timeout(value = TESTCASE_TIMEOUT, unit = TimeUnit.MILLISECONDS)\n    void assertWithTrailingSlash() {\n        DefaultFullHttpRequest requestWithoutSlash = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, \"/trailing/slash/\");\n        HttpClient.request(HOST, PORT, requestWithoutSlash, httpResponse -> {\n            assertThat(httpResponse.status().code(), is(200));\n            byte[] bytes = ByteBufUtil.getBytes(httpResponse.content());\n            String body = new String(bytes, StandardCharsets.UTF_8);\n            assertThat(body, is(\"with trailing slash\"));\n        }, TESTCASE_TIMEOUT);\n    }\n    \n    @AfterAll\n    static void tearDown() {\n        if (null != restfulService) {\n            restfulService.shutdown();\n        }\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/pojo/JobPojo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pojo;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\n/**\n * A simple POJO for test.\n */\n@Getter\n@Setter\npublic final class JobPojo {\n    \n    private String group;\n    \n    private String name;\n    \n    private String cron;\n    \n    private String description;\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/pojo/ResultDto.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.pojo;\n\nimport lombok.Builder;\nimport lombok.Getter;\n\n@Builder\n@Getter\npublic final class ResultDto<T> {\n    \n    private final int code;\n    \n    private final T data;\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/serializer/CustomTextPlainResponseBodySerializer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.serializer;\n\nimport io.netty.handler.codec.http.HttpHeaderValues;\n\nimport java.nio.charset.StandardCharsets;\n\n/**\n * Serializer for <code>text/plain</code>. Serialize String to bytes.\n */\npublic final class CustomTextPlainResponseBodySerializer implements ResponseBodySerializer {\n    \n    @Override\n    public String mimeType() {\n        return HttpHeaderValues.TEXT_PLAIN.toString();\n    }\n    \n    @Override\n    public byte[] serialize(final Object responseBody) {\n        if (responseBody instanceof String) {\n            return ((String) responseBody).getBytes(StandardCharsets.UTF_8);\n        }\n        if (responseBody instanceof byte[]) {\n            return (byte[]) responseBody;\n        }\n        throw new UnsupportedOperationException(\"Can not deserialize\" + responseBody.getClass());\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/serializer/ResponseBodySerializerFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.serializer;\n\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass ResponseBodySerializerFactoryTest {\n    \n    @Test\n    void assertGetJsonDefaultSerializer() {\n        ResponseBodySerializer serializer = ResponseBodySerializerFactory.getResponseBodySerializer(HttpHeaderValues.APPLICATION_JSON.toString());\n        assertNotNull(serializer);\n    }\n    \n    @Test\n    void assertSerializerNotFound() {\n        assertThrows(ResponseBodySerializerNotFoundException.class, () -> ResponseBodySerializerFactory.getResponseBodySerializer(\"Unknown\"));\n    }\n}\n"
  },
  {
    "path": "restful/src/test/java/org/apache/shardingsphere/elasticjob/restful/wrapper/QueryParameterMapTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.restful.wrapper;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Arrays;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\n\nclass QueryParameterMapTest {\n    \n    @Test\n    void assertGetFirst() {\n        QueryParameterMap queryParameterMap = new QueryParameterMap();\n        queryParameterMap.add(\"name\", \"foo\");\n        assertThat(queryParameterMap.getFirst(\"name\"), is(\"foo\"));\n        assertFalse(queryParameterMap.isEmpty());\n    }\n    \n    @Test\n    void assertConvertToSingleValueMap() {\n        Map<String, List<String>> queries = new LinkedHashMap<>(1 << 2);\n        queries.put(\"foo\", new LinkedList<>(Arrays.asList(\"first_foo\", \"second_foo\")));\n        queries.put(\"bar\", new LinkedList<>(Arrays.asList(\"first_bar\", \"second_bar\")));\n        QueryParameterMap queryParameterMap = new QueryParameterMap(queries);\n        Map<String, String> singleValueMap = queryParameterMap.toSingleValueMap();\n        assertThat(singleValueMap.get(\"foo\"), is(\"first_foo\"));\n        assertThat(singleValueMap.get(\"bar\"), is(\"first_bar\"));\n    }\n    \n    @Test\n    void assertGetEntrySet() {\n        QueryParameterMap queryParameterMap = new QueryParameterMap();\n        queryParameterMap.put(\"foo\", new LinkedList<>(Arrays.asList(\"first_foo\", \"second_foo\")));\n        queryParameterMap.put(\"bar\", new LinkedList<>(Arrays.asList(\"first_bar\", \"second_bar\")));\n        Set<Map.Entry<String, List<String>>> entrySet = queryParameterMap.entrySet();\n        assertThat(entrySet.size(), is(2));\n    }\n}\n"
  },
  {
    "path": "restful/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.restful.serializer.ResponseBodySerializer",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.restful.serializer.CustomTextPlainResponseBodySerializer\n"
  },
  {
    "path": "spring/boot-starter/README.md",
    "content": "# ElasticJob Spring Boot Starter\n\n## Getting Started\n\n### Add Dependencies\n\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-spring-boot-starter</artifactId>\n    <version>${latest.version}</version>\n</dependency>\n```\n\nTracing starter is optional.\nUser can provide a bean of `TracingConfiguration` manually.\n```xml\n<dependency>\n    <groupId>org.apache.shardingsphere.elasticjob</groupId>\n    <artifactId>elasticjob-tracing-spring-boot-starter</artifactId>\n    <version>${latest.version}</version>\n</dependency>\n```\n\n### Implement a ElasticJob\n\n```java\n@Component\npublic class SpringBootSimpleJob implements SimpleJob {\n\n    @Autowired\n    private FooRepository fooRepository;\n\n    @Override\n    public void execute(ShardingContext shardingContext) {\n        System.out.println(String.format(\"Item: %s | Time: %s | Thread: %s | %s\",\n                shardingContext.getShardingItem(), new SimpleDateFormat(\"HH:mm:ss\").format(new Date()), Thread.currentThread().getId(), \"SIMPLE\"));\n        List<Foo> data = fooRepository.findTodoData(shardingContext.getShardingParameter(), 10);\n        for (Foo each : data) {\n            fooRepository.setCompleted(each.getId());\n        }\n    }\n}\n```\n\n### Configure Registry Center, Jobs and Tracing Configuration\n\n`application.yml`\n```yaml\nelasticjob:\n  tracing:\n    type: RDB\n  regCenter:\n    serverLists: localhost:6181\n    namespace: elasticjob-springboot\n  jobs:\n    classed:\n      org.apache.shardingsphere.elasticjob.simple.job.SimpleJob:\n        - jobName: simpleJob\n          cron: 0/5 * * * * ?\n          shardingTotalCount: 3\n          shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n      org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob:\n        - jobName: dataflowJob\n          cron: 0/5 * * * * ?\n          shardingTotalCount: 3\n          shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou\n    typed:\n      SCRIPT:\n        - jobName: scriptJob\n          cron: 0/10 * * * * ?\n          shardingTotalCount: 3\n          props:\n            script.command.line: /home/sia/test/hello.sh\n```\n\n### Run it!\n\nLog fragments after started:\n```\nItem: 2 | Time: 14:18:00 | Thread: 391 | DATAFLOW FETCH\nItem: 0 | Time: 14:18:00 | Thread: 386 | DATAFLOW FETCH\nItem: 0 | Time: 14:18:00 | Thread: 387 | SIMPLE\nItem: 1 | Time: 14:18:00 | Thread: 389 | SIMPLE\nItem: 2 | Time: 14:18:00 | Thread: 393 | SIMPLE\nItem: 1 | Time: 14:18:00 | Thread: 388 | DATAFLOW FETCH\nItem: 1 | Time: 14:18:00 | Thread: 388 | DATAFLOW PROCESS\nItem: 0 | Time: 14:18:00 | Thread: 386 | DATAFLOW PROCESS\nItem: 2 | Time: 14:18:00 | Thread: 391 | DATAFLOW PROCESS\nSCRIPT Job: {\"jobName\":\"scriptJob\",\"taskId\":\"scriptJob@-@0,1,2@-@READY@-@192.168.3.233@-@28250\",\"shardingTotalCount\":3,\"jobParameter\":\"\",\"shardingItem\":1}\nSCRIPT Job: {\"jobName\":\"scriptJob\",\"taskId\":\"scriptJob@-@0,1,2@-@READY@-@192.168.3.233@-@28250\",\"shardingTotalCount\":3,\"jobParameter\":\"\",\"shardingItem\":2}\nSCRIPT Job: {\"jobName\":\"scriptJob\",\"taskId\":\"scriptJob@-@0,1,2@-@READY@-@192.168.3.233@-@28250\",\"shardingTotalCount\":3,\"jobParameter\":\"\",\"shardingItem\":0}\n```"
  },
  {
    "path": "spring/boot-starter/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-spring</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-spring-boot-starter</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-spring-core</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-test-util</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-configuration-processor</artifactId>\n            <optional>true</optional>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.awaitility</groupId>\n            <artifactId>awaitility</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/job/ElasticJobAutoConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job;\n\nimport org.apache.shardingsphere.elasticjob.spring.boot.reg.ElasticJobRegistryCenterConfiguration;\nimport org.apache.shardingsphere.elasticjob.spring.boot.reg.snapshot.ElasticJobSnapshotServiceConfiguration;\nimport org.apache.shardingsphere.elasticjob.spring.boot.tracing.ElasticJobTracingConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\n\n/**\n * ElasticJob auto configuration.\n */\n@Configuration(proxyBeanMethods = false)\n@AutoConfigureAfter(DataSourceAutoConfiguration.class)\n@ConditionalOnProperty(name = \"elasticjob.enabled\", havingValue = \"true\", matchIfMissing = true)\n@Import({ElasticJobRegistryCenterConfiguration.class, ElasticJobTracingConfiguration.class, ElasticJobSnapshotServiceConfiguration.class})\n@EnableConfigurationProperties(ElasticJobProperties.class)\npublic class ElasticJobAutoConfiguration {\n    \n    @Configuration(proxyBeanMethods = false)\n    @Import({ElasticJobBootstrapConfiguration.class, ScheduleJobBootstrapStartupRunner.class})\n    protected static class ElasticJobConfiguration {\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/job/ElasticJobBootstrapConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job;\n\nimport com.google.common.base.Preconditions;\nimport com.google.common.base.Strings;\nimport lombok.Setter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.spring.boot.tracing.TracingProperties;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.SmartInitializingSingleton;\nimport org.springframework.beans.factory.config.SingletonBeanRegistry;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport java.util.Map;\n\n/**\n * Job bootstrap configuration.\n */\n@Slf4j\npublic class ElasticJobBootstrapConfiguration implements SmartInitializingSingleton, ApplicationContextAware {\n    \n    @Setter\n    private ApplicationContext applicationContext;\n    \n    @Override\n    public void afterSingletonsInstantiated() {\n        log.info(\"creating Job Bootstrap Beans\");\n        createJobBootstrapBeans();\n        log.info(\"Job Bootstrap Beans created.\");\n    }\n    \n    /**\n     * Create job bootstrap instances and register them into container.\n     */\n    public void createJobBootstrapBeans() {\n        ElasticJobProperties elasticJobProperties = applicationContext.getBean(ElasticJobProperties.class);\n        SingletonBeanRegistry singletonBeanRegistry = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();\n        CoordinatorRegistryCenter registryCenter = applicationContext.getBean(CoordinatorRegistryCenter.class);\n        TracingConfiguration<?> tracingConfig = getTracingConfiguration();\n        constructJobBootstraps(elasticJobProperties, singletonBeanRegistry, registryCenter, tracingConfig);\n    }\n    \n    @SuppressWarnings(\"rawtypes\")\n    private TracingConfiguration<?> getTracingConfiguration() {\n        Map<String, TracingConfiguration> tracingConfigurationBeans = applicationContext.getBeansOfType(TracingConfiguration.class);\n        if (tracingConfigurationBeans.isEmpty()) {\n            return null;\n        }\n        if (1 == tracingConfigurationBeans.size()) {\n            return tracingConfigurationBeans.values().iterator().next();\n        }\n        throw new BeanCreationException(\"More than one [org.apache.shardingsphere.elasticjob.tracing.api.TracingConfiguration] beans found. \"\n                + \"Consider disabling [org.apache.shardingsphere.elasticjob.tracing.boot.ElasticJobTracingAutoConfiguration].\");\n    }\n    \n    private void constructJobBootstraps(final ElasticJobProperties elasticJobProperties, final SingletonBeanRegistry singletonBeanRegistry,\n                                        final CoordinatorRegistryCenter registryCenter, final TracingConfiguration<?> tracingConfig) {\n        for (Map.Entry<String, ElasticJobConfigurationProperties> entry : elasticJobProperties.getJobs().entrySet()) {\n            ElasticJobConfigurationProperties jobConfigurationProperties = entry.getValue();\n            Preconditions.checkArgument(null != jobConfigurationProperties.getElasticJobClass()\n                    || !Strings.isNullOrEmpty(jobConfigurationProperties.getElasticJobType()),\n                    \"Please specific [elasticJobClass] or [elasticJobType] under job configuration.\");\n            Preconditions.checkArgument(null == jobConfigurationProperties.getElasticJobClass()\n                    || Strings.isNullOrEmpty(jobConfigurationProperties.getElasticJobType()),\n                    \"[elasticJobClass] and [elasticJobType] are mutually exclusive.\");\n            if (null != jobConfigurationProperties.getElasticJobClass()) {\n                registerClassedJob(entry.getKey(), entry.getValue().getJobBootstrapBeanName(), singletonBeanRegistry, registryCenter, tracingConfig, jobConfigurationProperties);\n            } else if (!Strings.isNullOrEmpty(jobConfigurationProperties.getElasticJobType())) {\n                registerTypedJob(entry.getKey(), entry.getValue().getJobBootstrapBeanName(), singletonBeanRegistry, registryCenter, tracingConfig, jobConfigurationProperties);\n            }\n        }\n    }\n    \n    private void registerClassedJob(final String jobName, final String jobBootstrapBeanName, final SingletonBeanRegistry singletonBeanRegistry, final CoordinatorRegistryCenter registryCenter,\n                                    final TracingConfiguration<?> tracingConfig, final ElasticJobConfigurationProperties jobConfigurationProperties) {\n        JobConfiguration jobConfig = jobConfigurationProperties.toJobConfiguration(jobName);\n        jobExtraConfigurations(jobConfig, tracingConfig);\n        ElasticJob elasticJob = applicationContext.getBean(jobConfigurationProperties.getElasticJobClass());\n        if (Strings.isNullOrEmpty(jobConfig.getCron())) {\n            Preconditions.checkArgument(!Strings.isNullOrEmpty(jobBootstrapBeanName), \"The property [jobBootstrapBeanName] is required for One-off job.\");\n            singletonBeanRegistry.registerSingleton(jobBootstrapBeanName, new OneOffJobBootstrap(registryCenter, elasticJob, jobConfig));\n        } else {\n            String beanName = !Strings.isNullOrEmpty(jobBootstrapBeanName) ? jobBootstrapBeanName : jobConfig.getJobName() + \"ScheduleJobBootstrap\";\n            singletonBeanRegistry.registerSingleton(beanName, new ScheduleJobBootstrap(registryCenter, elasticJob, jobConfig));\n        }\n    }\n    \n    private void registerTypedJob(final String jobName, final String jobBootstrapBeanName, final SingletonBeanRegistry singletonBeanRegistry, final CoordinatorRegistryCenter registryCenter,\n                                  final TracingConfiguration<?> tracingConfig, final ElasticJobConfigurationProperties jobConfigurationProperties) {\n        JobConfiguration jobConfig = jobConfigurationProperties.toJobConfiguration(jobName);\n        jobExtraConfigurations(jobConfig, tracingConfig);\n        if (Strings.isNullOrEmpty(jobConfig.getCron())) {\n            Preconditions.checkArgument(!Strings.isNullOrEmpty(jobBootstrapBeanName), \"The property [jobBootstrapBeanName] is required for One-off job.\");\n            singletonBeanRegistry.registerSingleton(jobBootstrapBeanName, new OneOffJobBootstrap(registryCenter, jobConfigurationProperties.getElasticJobType(), jobConfig));\n        } else {\n            String beanName = !Strings.isNullOrEmpty(jobBootstrapBeanName) ? jobBootstrapBeanName : jobConfig.getJobName() + \"ScheduleJobBootstrap\";\n            singletonBeanRegistry.registerSingleton(beanName, new ScheduleJobBootstrap(registryCenter, jobConfigurationProperties.getElasticJobType(), jobConfig));\n        }\n    }\n    \n    private void jobExtraConfigurations(final JobConfiguration jobConfig, final TracingConfiguration<?> tracingConfig) {\n        if (null == tracingConfig) {\n            return;\n        }\n        TracingProperties tracingProperties = applicationContext.getBean(TracingProperties.class);\n        Preconditions.checkArgument(tracingProperties.getIncludeJobNames().isEmpty() || tracingProperties.getExcludeJobNames().isEmpty(),\n                \"[tracing.includeJobNames] and [tracing.excludeJobNames] are mutually exclusive.\");\n        if ((tracingProperties.getIncludeJobNames().isEmpty() || tracingProperties.getIncludeJobNames().contains(jobConfig.getJobName()))\n                && !tracingProperties.getExcludeJobNames().contains(jobConfig.getJobName())) {\n            jobConfig.getExtraConfigurations().add(tracingConfig);\n        }\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/job/ElasticJobConfigurationProperties.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\n\nimport java.util.Collection;\nimport java.util.LinkedList;\nimport java.util.Properties;\n\n/**\n * ElasticJob configuration properties.\n */\n@Getter\n@Setter\npublic final class ElasticJobConfigurationProperties {\n    \n    private Class<? extends ElasticJob> elasticJobClass;\n    \n    private String elasticJobType;\n    \n    private String cron;\n    \n    private String timeZone;\n    \n    private String jobBootstrapBeanName;\n    \n    private int shardingTotalCount;\n    \n    private String shardingItemParameters;\n    \n    private String jobParameter;\n    \n    private boolean monitorExecution;\n    \n    private boolean failover;\n    \n    private boolean misfire;\n    \n    private int maxTimeDiffSeconds = -1;\n    \n    private int reconcileIntervalMinutes;\n    \n    private String jobShardingStrategyType;\n    \n    private String jobExecutorThreadPoolSizeProviderType;\n    \n    private String jobErrorHandlerType;\n    \n    private Collection<String> jobListenerTypes = new LinkedList<>();\n    \n    private String description;\n    \n    private Properties props = new Properties();\n    \n    private boolean disabled;\n    \n    private boolean overwrite;\n    \n    /**\n     * Convert to job configuration.\n     *\n     * @param jobName job name\n     * @return job configuration\n     */\n    public JobConfiguration toJobConfiguration(final String jobName) {\n        JobConfiguration result = JobConfiguration.newBuilder(jobName, shardingTotalCount)\n                .cron(cron).timeZone(timeZone).shardingItemParameters(shardingItemParameters).jobParameter(jobParameter)\n                .monitorExecution(monitorExecution).failover(failover).misfire(misfire)\n                .maxTimeDiffSeconds(maxTimeDiffSeconds).reconcileIntervalMinutes(reconcileIntervalMinutes)\n                .jobShardingStrategyType(jobShardingStrategyType).jobExecutorThreadPoolSizeProviderType(jobExecutorThreadPoolSizeProviderType).jobErrorHandlerType(jobErrorHandlerType)\n                .jobListenerTypes(jobListenerTypes.toArray(new String[0])).description(description).disabled(disabled).overwrite(overwrite).build();\n        props.stringPropertyNames().forEach(each -> result.getProps().setProperty(each, props.getProperty(each)));\n        return result;\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/job/ElasticJobProperties.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * ElasticJob properties.\n */\n@Getter\n@Setter\n@ConfigurationProperties(prefix = \"elasticjob\")\npublic class ElasticJobProperties {\n    \n    private Map<String, ElasticJobConfigurationProperties> jobs = new LinkedHashMap<>();\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/job/ScheduleJobBootstrapStartupRunner.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job;\n\nimport lombok.Setter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\n\n/**\n * ElasticJob startup runner.\n */\n@Setter\n@Slf4j\npublic class ScheduleJobBootstrapStartupRunner implements CommandLineRunner, ApplicationContextAware {\n    \n    private ApplicationContext applicationContext;\n    \n    @Override\n    public void run(final String... args) {\n        log.info(\"Starting ElasticJob Bootstrap.\");\n        applicationContext.getBeansOfType(ScheduleJobBootstrap.class).values().forEach(ScheduleJobBootstrap::schedule);\n        log.info(\"ElasticJob Bootstrap started.\");\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/reg/ElasticJobRegistryCenterConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.reg;\n\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * ElasticJob registry center configuration.\n */\n@EnableConfigurationProperties(ZookeeperProperties.class)\npublic class ElasticJobRegistryCenterConfiguration {\n    \n    /**\n     * Create a zookeeper registry center bean via factory.\n     *\n     * @param zookeeperProperties factory\n     * @return zookeeper registry center\n     */\n    @Bean(initMethod = \"init\", destroyMethod = \"close\")\n    public ZookeeperRegistryCenter zookeeperRegistryCenter(final ZookeeperProperties zookeeperProperties) {\n        return new ZookeeperRegistryCenter(zookeeperProperties.toZookeeperConfiguration());\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/reg/ZookeeperProperties.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.reg;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n@Getter\n@Setter\n@ConfigurationProperties(prefix = \"elasticjob.reg-center\")\npublic class ZookeeperProperties {\n    \n    /**\n     * Server list of ZooKeeper.\n     *\n     * <p>\n     * Include IP addresses and ports,\n     * Multiple IP address split by comma.\n     * For example: host1:2181,host2:2181\n     * </p>\n     */\n    private String serverLists;\n    \n    /**\n     * Namespace.\n     */\n    private String namespace;\n    \n    /**\n     * Base sleep time milliseconds.\n     */\n    private int baseSleepTimeMilliseconds = 1000;\n    \n    /**\n     * Max sleep time milliseconds.\n     */\n    private int maxSleepTimeMilliseconds = 3000;\n    \n    /**\n     * Max retry times.\n     */\n    private int maxRetries = 3;\n    \n    /**\n     * Session timeout milliseconds.\n     */\n    private int sessionTimeoutMilliseconds;\n    \n    /**\n     * Connection timeout milliseconds.\n     */\n    private int connectionTimeoutMilliseconds;\n    \n    /**\n     * Zookeeper digest.\n     */\n    private String digest;\n    \n    /**\n     * Create ZooKeeper configuration.\n     *\n     * @return instance of ZooKeeper configuration\n     */\n    public ZookeeperConfiguration toZookeeperConfiguration() {\n        ZookeeperConfiguration result = new ZookeeperConfiguration(serverLists, namespace);\n        result.setBaseSleepTimeMilliseconds(baseSleepTimeMilliseconds);\n        result.setMaxSleepTimeMilliseconds(maxSleepTimeMilliseconds);\n        result.setMaxRetries(maxRetries);\n        result.setSessionTimeoutMilliseconds(sessionTimeoutMilliseconds);\n        result.setConnectionTimeoutMilliseconds(connectionTimeoutMilliseconds);\n        result.setDigest(digest);\n        return result;\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/reg/snapshot/ElasticJobSnapshotServiceConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.reg.snapshot;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Snapshot service configuration.\n */\n@ConditionalOnProperty(name = \"elasticjob.dump.enabled\", havingValue = \"true\", matchIfMissing = true)\n@EnableConfigurationProperties(SnapshotServiceProperties.class)\npublic class ElasticJobSnapshotServiceConfiguration {\n    \n    /**\n     * Create a Snapshot service bean and start listening.\n     *\n     * @param registryCenter registry center\n     * @param snapshotServiceProperties snapshot service properties\n     * @return a bean of snapshot service\n     */\n    @ConditionalOnProperty(name = \"elasticjob.dump.port\")\n    @Bean(initMethod = \"listen\", destroyMethod = \"close\")\n    public SnapshotService snapshotService(final CoordinatorRegistryCenter registryCenter, final SnapshotServiceProperties snapshotServiceProperties) {\n        return new SnapshotService(registryCenter, snapshotServiceProperties.getPort());\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/reg/snapshot/SnapshotServiceProperties.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.reg.snapshot;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Snapshot service properties.\n */\n@Getter\n@Setter\n@ConfigurationProperties(prefix = \"elasticjob.dump\")\npublic class SnapshotServiceProperties {\n    \n    private int port;\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/tracing/ElasticJobTracingConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.tracing;\n\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.lang.Nullable;\n\nimport javax.sql.DataSource;\n\n/**\n * ElasticJob tracing auto configuration.\n */\n@Configuration(proxyBeanMethods = false)\n@EnableConfigurationProperties(TracingProperties.class)\npublic class ElasticJobTracingConfiguration {\n    \n    @Configuration(proxyBeanMethods = false)\n    @ConditionalOnProperty(name = \"elasticjob.tracing.type\", havingValue = \"RDB\")\n    static class RDBTracingConfiguration {\n        \n        /**\n         * Create a bean of tracing DataSource.\n         *\n         * @param tracingProperties tracing Properties\n         * @return tracing DataSource\n         */\n        @Bean(\"tracingDataSource\")\n        public DataSource tracingDataSource(final TracingProperties tracingProperties) {\n            DataSourceProperties dataSource = tracingProperties.getDataSource();\n            if (dataSource == null) {\n                return null;\n            }\n            HikariDataSource tracingDataSource = new HikariDataSource();\n            tracingDataSource.setJdbcUrl(dataSource.getUrl());\n            BeanUtils.copyProperties(dataSource, tracingDataSource);\n            return tracingDataSource;\n        }\n        \n        /**\n         * Create a bean of tracing configuration.\n         *\n         * @param dataSource required by constructor\n         * @param tracingDataSource tracing ataSource\n         * @return a bean of tracing configuration\n         */\n        @Bean\n        public TracingConfiguration<DataSource> tracingConfiguration(@Qualifier(\"dataSource\") @Nullable final DataSource dataSource,\n                                                                     @Qualifier(\"tracingDataSource\") @Nullable final DataSource tracingDataSource) {\n            if (dataSource == null && tracingDataSource == null) {\n                throw new IllegalArgumentException(\"Neither dataSource nor tracingDataSource bean is required\");\n            }\n            return new TracingConfiguration<>(\"RDB\", null == tracingDataSource ? dataSource : tracingDataSource);\n        }\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/java/org/apache/shardingsphere/elasticjob/spring/boot/tracing/TracingProperties.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.tracing;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.NestedConfigurationProperty;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n@Getter\n@Setter\n@ConfigurationProperties(prefix = \"elasticjob.tracing\")\npublic class TracingProperties {\n    \n    private String type;\n    \n    @NestedConfigurationProperty\n    private DataSourceProperties dataSource;\n    \n    private Set<String> includeJobNames = new HashSet<>();\n    \n    private Set<String> excludeJobNames = new HashSet<>();\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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{\n  \"groups\": [\n    {\n      \"name\": \"elasticjob.reg-center\",\n      \"type\": \"org.apache.shardingsphere.elasticjob.spring.boot.reg.ZookeeperProperties\",\n      \"description\": \"Registry Center configurations.\"\n    },\n    {\n      \"name\": \"elasticjob.tracing\",\n      \"description\": \"Event Trace configurations.\"\n    },\n    {\n      \"name\": \"elasticjob.dump\",\n      \"description\": \"Snapshot service configurations.\"\n    }\n  ],\n  \"properties\": [\n    {\n      \"name\": \"elasticjob.reg-center.server-lists\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Include IP addresses and ports. Multiple IP address split by comma.\",\n      \"sourceType\": \"org.apache.shardingsphere.elasticjob.spring.boot.reg.ZookeeperProperties\"\n    },\n    {\n      \"name\": \"elasticjob.reg-center.namespace\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Namespace.\",\n      \"sourceType\": \"org.apache.shardingsphere.elasticjob.spring.boot.reg.ZookeeperProperties\"\n    },\n    {\n      \"name\": \"elasticjob.reg-center.base-sleep-time-milliseconds\",\n      \"type\": \"java.lang.Integer\",\n      \"defaultValue\": 1000,\n      \"description\": \"Base sleep time milliseconds.\",\n      \"sourceType\": \"org.apache.shardingsphere.elasticjob.spring.boot.reg.ZookeeperProperties\"\n    },\n    {\n      \"name\": \"elasticjob.reg-center.max-sleep-time-milliseconds\",\n      \"type\": \"java.lang.Integer\",\n      \"defaultValue\": 3000,\n      \"description\": \"Max sleep time milliseconds.\",\n      \"sourceType\": \"org.apache.shardingsphere.elasticjob.spring.boot.reg.ZookeeperProperties\"\n    },\n    {\n      \"name\": \"elasticjob.reg-center.max-retries\",\n      \"type\": \"java.lang.Integer\",\n      \"defaultValue\": 3,\n      \"description\": \"Max retry times.\",\n      \"sourceType\": \"org.apache.shardingsphere.elasticjob.spring.boot.reg.ZookeeperProperties\"\n    },\n    {\n      \"name\": \"elasticjob.reg-center.session-timeout-milliseconds\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Session timeout milliseconds.\",\n      \"sourceType\": \"org.apache.shardingsphere.elasticjob.spring.boot.reg.ZookeeperProperties\"\n    },\n    {\n      \"name\": \"elasticjob.reg-center.connection-timeout-milliseconds\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"Connection timeout milliseconds.\",\n      \"sourceType\": \"org.apache.shardingsphere.elasticjob.spring.boot.reg.ZookeeperProperties\"\n    },\n    {\n      \"name\": \"elasticjob.reg-center.digest\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Zookeeper digest.\",\n      \"sourceType\": \"org.apache.shardingsphere.elasticjob.spring.boot.reg.ZookeeperProperties\"\n    },\n    {\n      \"name\": \"elasticjob.tracing.type\",\n      \"type\": \"java.lang.String\",\n      \"description\": \"Type of Event Trace storage.\"\n    },\n    {\n      \"name\": \"elasticjob.tracing.includeJobNames\",\n      \"type\": \"java.util.Set<java.lang.String>\",\n      \"description\": \"include the specific job.\",\n      \"defaultValue\": null\n    },\n    {\n      \"name\": \"elasticjob.tracing.excludeJobNames\",\n      \"type\": \"java.util.Set<java.lang.String>\",\n      \"description\": \"exclude the specific job.\",\n      \"defaultValue\": null\n    },\n    {\n      \"name\": \"elasticjob.jobs\",\n      \"type\": \"java.util.Map<java.lang.String,org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobConfigurationProperties>\"\n    },\n    {\n      \"name\": \"elasticjob.dump.port\",\n      \"type\": \"java.lang.Integer\",\n      \"description\": \"A port for configuring SnapshotService.\",\n      \"sourceType\": \"org.apache.shardingsphere.elasticjob.spring.boot.reg.snapshot.SnapshotServiceProperties\"\n    },\n    {\n      \"name\": \"elasticjob.dump.enabled\",\n      \"type\": \"java.lang.Boolean\",\n      \"defaultValue\": true,\n      \"description\": \"Enable SnapshotService.\"\n    }\n  ],\n  \"hints\": [\n    {\n      \"name\": \"elasticjob.tracing.type\",\n      \"values\": [\n        {\n          \"value\": \"RDB\",\n          \"description\": \"Using JDBC DataSource for Event Trace.\"\n        }\n      ]\n    },\n    {\n      \"name\": \"elasticjob.jobs.keys\",\n      \"values\": [\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "spring/boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobAutoConfiguration\n"
  },
  {
    "path": "spring/boot-starter/src/main/resources/META-INF/spring.factories",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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#\norg.springframework.boot.autoconfigure.EnableAutoConfiguration=\\\n  org.apache.shardingsphere.elasticjob.spring.boot.job.ElasticJobAutoConfiguration\n"
  },
  {
    "path": "spring/boot-starter/src/main/resources/META-INF/spring.provides",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nprovides: elasticjob-spring-boot-starter\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/ElasticJobConfigurationPropertiesTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Collections;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass ElasticJobConfigurationPropertiesTest {\n    \n    @Test\n    void assertToJobConfiguration() {\n        ElasticJobConfigurationProperties properties = new ElasticJobConfigurationProperties();\n        properties.setElasticJobClass(ElasticJob.class);\n        properties.setElasticJobType(\"jobType\");\n        properties.setCron(\"cron\");\n        properties.setTimeZone(\"timeZone\");\n        properties.setJobBootstrapBeanName(\"beanName\");\n        properties.setShardingTotalCount(3);\n        properties.setShardingItemParameters(\"a=1,b=2\");\n        properties.setJobParameter(\"testParam\");\n        properties.setMonitorExecution(true);\n        properties.setFailover(true);\n        properties.setMisfire(true);\n        properties.setMaxTimeDiffSeconds(1);\n        properties.setReconcileIntervalMinutes(2);\n        properties.setJobShardingStrategyType(\"strategyType\");\n        properties.setJobExecutorThreadPoolSizeProviderType(\"executorType\");\n        properties.setJobErrorHandlerType(\"errorHandlerType\");\n        properties.setJobListenerTypes(Collections.singleton(\"listenerType\"));\n        properties.setDescription(\"test desc\");\n        properties.setDisabled(true);\n        properties.setOverwrite(true);\n        properties.getProps().setProperty(\"test\", \"test\");\n        JobConfiguration actual = properties.toJobConfiguration(\"testJob\");\n        assertThat(actual.getJobName(), is(\"testJob\"));\n        assertThat(actual.getShardingTotalCount(), is(properties.getShardingTotalCount()));\n        assertThat(actual.getCron(), is(properties.getCron()));\n        assertThat(actual.getTimeZone(), is(properties.getTimeZone()));\n        assertThat(actual.getShardingItemParameters(), is(properties.getShardingItemParameters()));\n        assertThat(actual.getJobParameter(), is(properties.getJobParameter()));\n        assertThat(actual.getMaxTimeDiffSeconds(), is(properties.getMaxTimeDiffSeconds()));\n        assertThat(actual.getReconcileIntervalMinutes(), is(properties.getReconcileIntervalMinutes()));\n        assertThat(actual.getJobShardingStrategyType(), is(properties.getJobShardingStrategyType()));\n        assertThat(actual.getJobExecutorThreadPoolSizeProviderType(), is(properties.getJobExecutorThreadPoolSizeProviderType()));\n        assertThat(actual.getJobErrorHandlerType(), is(properties.getJobErrorHandlerType()));\n        assertThat(actual.getJobListenerTypes().toArray(), is(properties.getJobListenerTypes().toArray()));\n        assertThat(actual.getDescription(), is(properties.getDescription()));\n        assertThat(actual.isDisabled(), is(properties.isDisabled()));\n        assertThat(actual.isOverwrite(), is(properties.isOverwrite()));\n        assertThat(actual.isMisfire(), is(properties.isMisfire()));\n        assertThat(actual.isFailover(), is(properties.isFailover()));\n        assertThat(actual.isMonitorExecution(), is(properties.isMonitorExecution()));\n        assertThat(actual.getProps().size(), is(properties.getProps().size()));\n        assertThat(actual.getProps().getProperty(\"test\"), is(properties.getProps().getProperty(\"test\")));\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/ElasticJobSpringBootScannerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job;\n\nimport org.apache.curator.CuratorZookeeperClient;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.test.TestingServer;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job.impl.AnnotationCustomJob;\nimport org.apache.shardingsphere.elasticjob.spring.core.scanner.ElasticJobScan;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n@DirtiesContext\n@SpringBootTest(properties = \"spring.main.banner-mode=off\")\n@ActiveProfiles(\"elasticjob\")\n@ElasticJobScan(basePackages = \"org.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job.impl\")\nclass ElasticJobSpringBootScannerTest {\n    \n    private static TestingServer testingServer;\n    \n    @Autowired\n    private ApplicationContext applicationContext;\n    \n    @DynamicPropertySource\n    static void elasticjobProperties(final DynamicPropertyRegistry registry) {\n        registry.add(\"elasticjob.regCenter.serverLists\", () -> testingServer.getConnectString());\n    }\n    \n    @BeforeAll\n    static void init() throws Exception {\n        testingServer = new TestingServer();\n        try (\n                CuratorZookeeperClient client = new CuratorZookeeperClient(testingServer.getConnectString(),\n                        60000, 500, null,\n                        new ExponentialBackoffRetry(500, 3, 1500))) {\n            client.start();\n            Awaitility.await().atMost(Duration.ofSeconds(30L)).ignoreExceptions().until(client::isConnected);\n        }\n        AnnotationCustomJob.reset();\n    }\n    \n    @AfterAll\n    static void afterAll() throws IOException {\n        testingServer.close();\n    }\n    \n    @Test\n    void assertDefaultBeanNameWithTypeJob() {\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).until(AnnotationCustomJob::isCompleted);\n        assertTrue(AnnotationCustomJob.isCompleted());\n        assertNotNull(applicationContext);\n        assertNotNull(applicationContext.getBean(\"annotationCustomJobSchedule\", ScheduleJobBootstrap.class));\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/ElasticJobSpringBootTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job;\n\nimport org.apache.curator.CuratorZookeeperClient;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.test.TestingServer;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobExtraConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.JobBootstrap;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobScheduler;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job.impl.CustomTestJob;\nimport org.apache.shardingsphere.elasticjob.spring.boot.reg.ZookeeperProperties;\nimport org.apache.shardingsphere.elasticjob.spring.boot.tracing.TracingProperties;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.sql.SQLException;\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertInstanceOf;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n@DirtiesContext\n@SpringBootTest(properties = \"spring.main.banner-mode=off\")\n@SpringBootApplication\n@ActiveProfiles(\"elasticjob\")\nclass ElasticJobSpringBootTest {\n    \n    private static TestingServer testingServer;\n    \n    @Autowired\n    private ApplicationContext applicationContext;\n    \n    @DynamicPropertySource\n    static void elasticjobProperties(final DynamicPropertyRegistry registry) {\n        registry.add(\"elasticjob.regCenter.serverLists\", () -> testingServer.getConnectString());\n    }\n    \n    @BeforeAll\n    static void init() throws Exception {\n        testingServer = new TestingServer();\n        try (\n                CuratorZookeeperClient client = new CuratorZookeeperClient(testingServer.getConnectString(),\n                        60000, 500, null,\n                        new ExponentialBackoffRetry(500, 3, 1500))) {\n            client.start();\n            Awaitility.await().atMost(Duration.ofSeconds(30L)).ignoreExceptions().until(client::isConnected);\n        }\n    }\n    \n    @AfterAll\n    static void afterAll() throws IOException {\n        testingServer.close();\n    }\n    \n    @Test\n    void assertZookeeperProperties() {\n        assertNotNull(applicationContext);\n        ZookeeperProperties actual = applicationContext.getBean(ZookeeperProperties.class);\n        assertThat(actual.getServerLists(), is(testingServer.getConnectString()));\n        assertThat(actual.getNamespace(), is(\"elasticjob-spring-boot-starter\"));\n    }\n    \n    @Test\n    void assertRegistryCenterCreation() {\n        assertNotNull(applicationContext);\n        ZookeeperRegistryCenter zookeeperRegistryCenter = applicationContext.getBean(ZookeeperRegistryCenter.class);\n        assertNotNull(zookeeperRegistryCenter);\n        zookeeperRegistryCenter.persist(\"/foo\", \"bar\");\n        assertThat(zookeeperRegistryCenter.get(\"/foo\"), is(\"bar\"));\n    }\n    \n    @Test\n    void assertTracingConfigurationCreation() throws SQLException {\n        assertNotNull(applicationContext);\n        TracingConfiguration<?> tracingConfig = applicationContext.getBean(TracingConfiguration.class);\n        assertNotNull(tracingConfig);\n        assertThat(tracingConfig.getType(), is(\"RDB\"));\n        assertInstanceOf(DataSource.class, tracingConfig.getTracingStorageConfiguration().getStorage());\n        DataSource dataSource = (DataSource) tracingConfig.getTracingStorageConfiguration().getStorage();\n        assertNotNull(dataSource.getConnection());\n    }\n    \n    @Test\n    void assertTracingProperties() {\n        assertNotNull(applicationContext);\n        TracingProperties tracingProperties = applicationContext.getBean(TracingProperties.class);\n        assertNotNull(tracingProperties);\n        assertTrue(tracingProperties.getIncludeJobNames().isEmpty());\n        Set<String> excludeJobNames = new HashSet<>();\n        excludeJobNames.add(\"customTestJob\");\n        assertThat(tracingProperties.getExcludeJobNames(), is(excludeJobNames));\n    }\n    \n    @Test\n    void assertElasticJobProperties() {\n        assertNotNull(applicationContext);\n        ElasticJobProperties elasticJobProperties = applicationContext.getBean(ElasticJobProperties.class);\n        assertNotNull(elasticJobProperties);\n        assertNotNull(elasticJobProperties.getJobs());\n        assertThat(elasticJobProperties.getJobs().size(), is(4));\n        ElasticJobConfigurationProperties customTestJobProperties = elasticJobProperties.getJobs().get(\"customTestJob\");\n        assertNotNull(customTestJobProperties);\n        assertThat(customTestJobProperties.getElasticJobClass(), is(CustomTestJob.class));\n        assertThat(customTestJobProperties.getJobBootstrapBeanName(), is(\"customTestJobBean\"));\n        assertThat(customTestJobProperties.getShardingTotalCount(), is(3));\n        assertNull(customTestJobProperties.getElasticJobType());\n        assertThat(customTestJobProperties.getJobListenerTypes().size(), is(2));\n        assertThat(customTestJobProperties.getJobListenerTypes(), is(Arrays.asList(\"NOOP\", \"LOG\")));\n        ElasticJobConfigurationProperties printTestJobProperties = elasticJobProperties.getJobs().get(\"printTestJob\");\n        assertNotNull(printTestJobProperties);\n        assertNull(printTestJobProperties.getElasticJobClass());\n        assertThat(printTestJobProperties.getElasticJobType(), is(\"PRINT\"));\n        assertThat(printTestJobProperties.getJobBootstrapBeanName(), is(\"printTestJobBean\"));\n        assertThat(printTestJobProperties.getShardingTotalCount(), is(3));\n        assertTrue(printTestJobProperties.getJobListenerTypes().isEmpty());\n        assertThat(printTestJobProperties.getProps().size(), is(1));\n        assertThat(printTestJobProperties.getProps().getProperty(\"print.content\"), is(\"test print job\"));\n    }\n    \n    @Test\n    void assertJobScheduleCreation() {\n        Awaitility.await().atLeast(100L, TimeUnit.MILLISECONDS).atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> {\n            assertNotNull(applicationContext);\n            Map<String, ElasticJob> elasticJobBeans = applicationContext.getBeansOfType(ElasticJob.class);\n            assertFalse(elasticJobBeans.isEmpty());\n            Map<String, JobBootstrap> jobBootstrapBeans = applicationContext.getBeansOfType(JobBootstrap.class);\n            assertFalse(jobBootstrapBeans.isEmpty());\n        });\n    }\n    \n    @Test\n    void assertOneOffJobBootstrapBeanName() {\n        assertNotNull(applicationContext);\n        OneOffJobBootstrap customTestJobBootstrap = applicationContext.getBean(\"customTestJobBean\", OneOffJobBootstrap.class);\n        assertNotNull(customTestJobBootstrap);\n        Collection<JobExtraConfiguration> extraConfigs = ((JobScheduler) ReflectionUtils.getFieldValue(customTestJobBootstrap, \"jobScheduler\")).getJobConfig().getExtraConfigurations();\n        assertThat(extraConfigs.size(), is(0));\n        OneOffJobBootstrap printTestJobBootstrap = applicationContext.getBean(\"printTestJobBean\", OneOffJobBootstrap.class);\n        extraConfigs = ((JobScheduler) ReflectionUtils.getFieldValue(printTestJobBootstrap, \"jobScheduler\")).getJobConfig().getExtraConfigurations();\n        assertThat(extraConfigs.size(), is(1));\n    }\n    \n    @Test\n    void assertDefaultBeanNameWithClassJob() {\n        assertNotNull(applicationContext);\n        assertNotNull(applicationContext.getBean(\"defaultBeanNameClassJobScheduleJobBootstrap\", ScheduleJobBootstrap.class));\n    }\n    \n    @Test\n    void assertDefaultBeanNameWithTypeJob() {\n        assertNotNull(applicationContext);\n        assertNotNull(applicationContext.getBean(\"defaultBeanNameTypeJobScheduleJobBootstrap\", ScheduleJobBootstrap.class));\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/executor/CustomClassedJobExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job.executor;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor;\nimport org.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job.CustomJob;\n\npublic final class CustomClassedJobExecutor implements ClassedJobItemExecutor<CustomJob> {\n    \n    @Override\n    public void process(final CustomJob elasticJob, final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService, final ShardingContext shardingContext) {\n        elasticJob.execute(shardingContext);\n    }\n    \n    @Override\n    public Class<CustomJob> getElasticJobClass() {\n        return CustomJob.class;\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/executor/PrintJobExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job.executor;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.TypedJobItemExecutor;\n\n@Slf4j\npublic final class PrintJobExecutor implements TypedJobItemExecutor {\n    \n    @Override\n    public void process(final ElasticJob elasticJob, final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService, final ShardingContext shardingContext) {\n        log.info(jobConfig.getProps().getProperty(PrintJobProperties.CONTENT_KEY));\n    }\n    \n    @Override\n    public String getType() {\n        return \"PRINT\";\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/executor/PrintJobProperties.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job.executor;\n\npublic final class PrintJobProperties {\n    \n    public static final String CONTENT_KEY = \"print.content\";\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/fixture/job/CustomJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\npublic interface CustomJob extends ElasticJob {\n    \n    /**\n     * Execute custom job.\n     *\n     * @param shardingContext sharding context\n     */\n    void execute(ShardingContext shardingContext);\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/fixture/job/impl/AnnotationCustomJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job.impl;\n\nimport lombok.Getter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobConfiguration;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobProp;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job.CustomJob;\nimport org.springframework.transaction.annotation.Transactional;\n\n@Slf4j\n@Transactional(rollbackFor = Exception.class)\n@ElasticJobConfiguration(\n        jobName = \"annotationCustomJobSchedule\",\n        description = \"desc\",\n        shardingTotalCount = 3,\n        shardingItemParameters = \"0=a,1=b,2=c\",\n        cron = \"*/1 * * * * ?\",\n        props = {\n                @ElasticJobProp(key = \"print.title\", value = \"test title\"),\n                @ElasticJobProp(key = \"print.content\", value = \"test content\")\n        })\npublic class AnnotationCustomJob implements CustomJob {\n    \n    @Getter\n    private static volatile boolean completed;\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        log.info(\"AnnotationCustomJob execut\");\n        completed = true;\n    }\n    \n    /**\n     * Set completed to false.\n     */\n    public static void reset() {\n        completed = false;\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/fixture/job/impl/CustomTestJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job.impl;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job.CustomJob;\nimport org.apache.shardingsphere.elasticjob.spring.boot.job.repository.BarRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Component\n@Slf4j\n@Transactional(rollbackFor = Exception.class)\npublic class CustomTestJob implements CustomJob {\n    \n    @Autowired\n    private BarRepository barRepository;\n    \n    public CustomTestJob() {\n        log.info(\"CustomTestJob init\");\n    }\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        int i = shardingContext.getShardingItem();\n        List<String> results = new ArrayList<>();\n        String data;\n        while (null != (data = barRepository.getById(i))) {\n            results.add(data);\n            i += shardingContext.getShardingTotalCount();\n        }\n        log.info(\"{}\", results);\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/fixture/listener/LogElasticJobListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job.fixture.listener;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\n\n/**\n * Log elastic job listener.\n */\n@Slf4j\npublic final class LogElasticJobListener implements ElasticJobListener {\n    \n    @Override\n    public void beforeJobExecuted(final ShardingContexts shardingContexts) {\n        log.info(\"Before job executed. {}\", shardingContexts);\n    }\n    \n    @Override\n    public void afterJobExecuted(final ShardingContexts shardingContexts) {\n        log.info(\"After job executed. {}\", shardingContexts);\n    }\n    \n    @Override\n    public String getType() {\n        return \"LOG\";\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/fixture/listener/NoopElasticJobListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job.fixture.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\n\n/**\n * No operation elastic job listener.\n */\npublic final class NoopElasticJobListener implements ElasticJobListener {\n    \n    @Override\n    public void beforeJobExecuted(final ShardingContexts shardingContexts) {\n    }\n    \n    @Override\n    public void afterJobExecuted(final ShardingContexts shardingContexts) {\n    }\n    \n    @Override\n    public String getType() {\n        return \"NOOP\";\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/repository/BarRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job.repository;\n\n/**\n * Bar Repository.\n */\npublic interface BarRepository {\n    \n    /**\n     * Get data by ID.\n     *\n     * @param id ID\n     * @return data\n     */\n    String getById(int id);\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/job/repository/impl/BarRepositoryImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.job.repository.impl;\n\nimport org.apache.shardingsphere.elasticjob.spring.boot.job.repository.BarRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic class BarRepositoryImpl implements BarRepository {\n    \n    private static final String[] DATA = {\"zero\", \"one\", \"two\", \"three\", \"four\", \"five\", \"six\", \"seven\", \"eight\", \"nine\"};\n    \n    @Override\n    public String getById(final int id) {\n        return id >= 0 && id < DATA.length ? DATA[id] : null;\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/reg/ZookeeperPropertiesTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.reg;\n\nimport org.apache.curator.test.InstanceSpec;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass ZookeeperPropertiesTest {\n    \n    @Test\n    void assertToZookeeperConfiguration() {\n        ZookeeperProperties properties = new ZookeeperProperties();\n        properties.setServerLists(\"localhost:\" + InstanceSpec.getRandomPort());\n        properties.setNamespace(\"test\");\n        properties.setBaseSleepTimeMilliseconds(2000);\n        properties.setMaxSleepTimeMilliseconds(4000);\n        properties.setMaxRetries(5);\n        properties.setSessionTimeoutMilliseconds(5000);\n        properties.setConnectionTimeoutMilliseconds(6000);\n        properties.setDigest(\"digest\");\n        ZookeeperConfiguration actual = properties.toZookeeperConfiguration();\n        assertThat(actual.getServerLists(), is(properties.getServerLists()));\n        assertThat(actual.getNamespace(), is(properties.getNamespace()));\n        assertThat(actual.getBaseSleepTimeMilliseconds(), is(properties.getBaseSleepTimeMilliseconds()));\n        assertThat(actual.getMaxSleepTimeMilliseconds(), is(properties.getMaxSleepTimeMilliseconds()));\n        assertThat(actual.getMaxRetries(), is(properties.getMaxRetries()));\n        assertThat(actual.getSessionTimeoutMilliseconds(), is(properties.getSessionTimeoutMilliseconds()));\n        assertThat(actual.getConnectionTimeoutMilliseconds(), is(properties.getConnectionTimeoutMilliseconds()));\n        assertThat(actual.getDigest(), is(properties.getDigest()));\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/reg/snapshot/ElasticJobSnapshotServiceConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.reg.snapshot;\n\nimport org.apache.curator.CuratorZookeeperClient;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.test.InstanceSpec;\nimport org.apache.curator.test.TestingServer;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\nimport java.io.IOException;\nimport java.time.Duration;\n\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\n\n@SpringBootTest(properties = \"spring.main.banner-mode=off\")\n@SpringBootApplication\n@ActiveProfiles(\"snapshot\")\nclass ElasticJobSnapshotServiceConfigurationTest {\n    \n    private static TestingServer testingServer;\n    \n    @Autowired\n    private ApplicationContext applicationContext;\n    \n    @DynamicPropertySource\n    static void elasticjobProperties(final DynamicPropertyRegistry registry) {\n        registry.add(\"elasticjob.regCenter.serverLists\", () -> testingServer.getConnectString());\n        registry.add(\"elasticjob.dump.port\", InstanceSpec::getRandomPort);\n    }\n    \n    @BeforeAll\n    static void init() throws Exception {\n        testingServer = new TestingServer();\n        try (\n                CuratorZookeeperClient client = new CuratorZookeeperClient(testingServer.getConnectString(),\n                        60000, 500, null,\n                        new ExponentialBackoffRetry(500, 3, 1500))) {\n            client.start();\n            Awaitility.await().atMost(Duration.ofSeconds(30L)).ignoreExceptions().until(client::isConnected);\n        }\n    }\n    \n    @AfterAll\n    static void afterAll() throws IOException {\n        testingServer.close();\n    }\n    \n    @Test\n    void assertSnapshotServiceConfiguration() {\n        assertNotNull(applicationContext);\n        assertNotNull(applicationContext.getBean(SnapshotService.class));\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/java/org/apache/shardingsphere/elasticjob/spring/boot/tracing/TracingConfigurationTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.boot.tracing;\n\nimport org.apache.curator.CuratorZookeeperClient;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.test.TestingServer;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.ResolvableType;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.time.Duration;\n\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\n@SpringBootTest(properties = \"spring.main.banner-mode=off\")\n@SpringBootApplication\n@ActiveProfiles(\"tracing\")\nclass TracingConfigurationTest {\n    \n    private static TestingServer testingServer;\n    \n    @Autowired\n    private ApplicationContext applicationContext;\n    \n    @DynamicPropertySource\n    static void elasticjobProperties(final DynamicPropertyRegistry registry) {\n        registry.add(\"elasticjob.regCenter.serverLists\", () -> testingServer.getConnectString());\n    }\n    \n    @BeforeAll\n    static void init() throws Exception {\n        testingServer = new TestingServer();\n        try (\n                CuratorZookeeperClient client = new CuratorZookeeperClient(testingServer.getConnectString(),\n                        60000, 500, null,\n                        new ExponentialBackoffRetry(500, 3, 1500))) {\n            client.start();\n            Awaitility.await().atMost(Duration.ofSeconds(30L)).ignoreExceptions().until(client::isConnected);\n        }\n    }\n    \n    @AfterAll\n    static void afterAll() throws IOException {\n        testingServer.close();\n    }\n    \n    @Test\n    void assertNotRDBConfiguration() {\n        assertNotNull(applicationContext);\n        assertFalse(applicationContext.containsBean(\"tracingDataSource\"));\n        ObjectProvider<Object> provider = applicationContext.getBeanProvider(ResolvableType.forClassWithGenerics(TracingConfiguration.class, DataSource.class));\n        assertNull(provider.getIfAvailable());\n    }\n}\n"
  },
  {
    "path": "spring/boot-starter/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.spring.boot.job.executor.CustomClassedJobExecutor\n"
  },
  {
    "path": "spring/boot-starter/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.TypedJobItemExecutor",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.spring.boot.job.executor.PrintJobExecutor\n"
  },
  {
    "path": "spring/boot-starter/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.spring.boot.job.fixture.listener.NoopElasticJobListener\norg.apache.shardingsphere.elasticjob.spring.boot.job.fixture.listener.LogElasticJobListener\n"
  },
  {
    "path": "spring/boot-starter/src/test/resources/application-elasticjob.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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# `elasticjob.regCenter.serverLists` is dynamically defined in `org.springframework.test.context.DynamicPropertySource`\nspring:\n  datasource:\n    url: jdbc:h2:mem:job_event_storage\n    driver-class-name: org.h2.Driver\n    username: sa\n    password:\n\nelasticjob:\n  tracing:\n    type: RDB\n    excludeJobNames: [customTestJob]\n  regCenter:\n    namespace: elasticjob-spring-boot-starter\n  jobs:\n    customTestJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job.impl.CustomTestJob\n      jobBootstrapBeanName: customTestJobBean\n      shardingTotalCount: 3\n      jobListenerTypes:\n        - NOOP\n        - LOG\n    printTestJob:\n      elasticJobType: PRINT\n      jobBootstrapBeanName: printTestJobBean\n      shardingTotalCount: 3\n      props:\n        print.content: \"test print job\"\n    defaultBeanNameClassJob:\n      cron: 0/5 * * * * ?\n      timeZome: GMT+08:00\n      elasticJobClass: org.apache.shardingsphere.elasticjob.spring.boot.job.fixture.job.impl.CustomTestJob\n      shardingTotalCount: 3\n    defaultBeanNameTypeJob:\n      cron: 0/5 * * * * ?\n      elasticJobType: PRINT\n      shardingTotalCount: 3\n      props:\n        print.content: \"test print job\"\n"
  },
  {
    "path": "spring/boot-starter/src/test/resources/application-snapshot.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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# `elasticjob.regCenter.serverLists` is dynamically defined in `org.springframework.test.context.DynamicPropertySource`\n# `elasticjob.dump.port` is dynamically defined in `org.springframework.test.context.DynamicPropertySource`\nelasticjob:\n  regCenter:\n    namespace: elasticjob-spring-boot-starter\n"
  },
  {
    "path": "spring/boot-starter/src/test/resources/application-tracing.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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# `elasticjob.regCenter.serverLists` is dynamically defined in `org.springframework.test.context.DynamicPropertySource`\nelasticjob:\n  regCenter:\n    namespace: elasticjob-spring-boot-starter\n"
  },
  {
    "path": "spring/boot-starter/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <level value=\"WARN\" />\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.zookeeper\" level=\"ERROR\" />\n    <logger name=\"org.apache.curator\" level=\"ERROR\" />\n</configuration>\n"
  },
  {
    "path": "spring/core/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-spring</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-spring-core</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-bootstrap</artifactId>\n            <version>${project.parent.version}</version>\n            <exclusions>\n                <exclusion>\n                    <groupId>com.zaxxer</groupId>\n                    <artifactId>HikariCP-java7</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context-support</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "spring/core/src/main/java/org/apache/shardingsphere/elasticjob/spring/core/scanner/ClassPathJobScanner.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.core.scanner;\n\nimport org.apache.commons.lang3.StringUtils;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.springframework.beans.factory.config.BeanDefinitionHolder;\nimport org.springframework.beans.factory.config.RuntimeBeanReference;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.annotation.ClassPathBeanDefinitionScanner;\nimport org.springframework.context.annotation.ScannedGenericBeanDefinition;\nimport org.springframework.core.type.filter.AnnotationTypeFilter;\n\nimport java.util.Objects;\nimport java.util.Set;\n\n/**\n * A {@link ClassPathBeanDefinitionScanner} that registers ScheduleJobBootstrap by {@code basePackage}.\n *\n * @see ScheduleJobBootstrap\n */\npublic class ClassPathJobScanner extends ClassPathBeanDefinitionScanner {\n    \n    public ClassPathJobScanner(final BeanDefinitionRegistry registry) {\n        super(registry, false);\n    }\n    \n    /**\n     * Calls the parent search that will search and register all the candidates by {@code ElasticJobConfiguration}.\n     *\n     * @param basePackages the packages to check for annotated classes\n     */\n    @Override\n    protected Set<BeanDefinitionHolder> doScan(final String... basePackages) {\n        addIncludeFilter(new AnnotationTypeFilter(ElasticJobConfiguration.class));\n        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);\n        if (!beanDefinitions.isEmpty()) {\n            processBeanDefinitions(beanDefinitions);\n        }\n        return beanDefinitions;\n    }\n    \n    private void processBeanDefinitions(final Set<BeanDefinitionHolder> beanDefinitions) {\n        BeanDefinitionRegistry registry = getRegistry();\n        for (BeanDefinitionHolder holder : beanDefinitions) {\n            ScannedGenericBeanDefinition definition = (ScannedGenericBeanDefinition) holder.getBeanDefinition();\n            Class<?> jobClass;\n            try {\n                jobClass = Class.forName(definition.getMetadata().getClassName());\n            } catch (ClassNotFoundException ex) {\n                // TODO： log\n                continue;\n            }\n            ElasticJobConfiguration jobAnnotation = jobClass.getAnnotation(ElasticJobConfiguration.class);\n            String registryCenter = jobAnnotation.registryCenter();\n            BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(ScheduleJobBootstrap.class);\n            factory.setInitMethodName(\"schedule\");\n            if (!StringUtils.isEmpty(registryCenter)) {\n                factory.addConstructorArgReference(registryCenter);\n            } else {\n                factory.addConstructorArgValue(new RuntimeBeanReference(CoordinatorRegistryCenter.class));\n            }\n            factory.addConstructorArgReference(Objects.requireNonNull(holder.getBeanName()));\n            registry.registerBeanDefinition(jobAnnotation.jobName(), factory.getBeanDefinition());\n        }\n    }\n}\n"
  },
  {
    "path": "spring/core/src/main/java/org/apache/shardingsphere/elasticjob/spring/core/scanner/ElasticJobScan.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.core.scanner;\n\nimport org.springframework.context.annotation.Import;\n\nimport java.lang.annotation.Documented;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * Use this annotation to register Elastic job.\n */\n@Documented\n@Retention(RetentionPolicy.RUNTIME)\n@Import(ElasticJobScanRegistrar.class)\n@Target(ElementType.TYPE)\npublic @interface ElasticJobScan {\n    \n    /**\n     * Alias for the {@link #basePackages()} attribute.\n     *\n     * @return Base packages name\n     */\n    String[] value() default \"\";\n    \n    /**\n     * Base packages to scan for Elastic job.\n     *\n     * @return Base packages name\n     */\n    String[] basePackages() default {};\n}\n"
  },
  {
    "path": "spring/core/src/main/java/org/apache/shardingsphere/elasticjob/spring/core/scanner/ElasticJobScanRegistrar.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.core.scanner;\n\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.context.annotation.ImportBeanDefinitionRegistrar;\nimport org.springframework.core.annotation.AnnotationAttributes;\nimport org.springframework.core.type.AnnotationMetadata;\nimport org.springframework.util.StringUtils;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * A {@link ImportBeanDefinitionRegistrar} to allow annotation configuration of Elastic Job scanning.\n *\n * @see ClassPathJobScanner\n */\npublic class ElasticJobScanRegistrar implements ImportBeanDefinitionRegistrar {\n    \n    @Override\n    public void registerBeanDefinitions(final AnnotationMetadata importingClassMetadata,\n                                        final BeanDefinitionRegistry registry) {\n        AnnotationAttributes elasticJobScanAttrs =\n                AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(ElasticJobScan.class.getName()));\n        if (elasticJobScanAttrs != null) {\n            registerBeanDefinitions(importingClassMetadata, elasticJobScanAttrs, registry);\n        }\n    }\n    \n    private void registerBeanDefinitions(final AnnotationMetadata annoMeta, final AnnotationAttributes annoAttrs,\n                                         final BeanDefinitionRegistry registry) {\n        BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(JobScannerConfiguration.class);\n        \n        List<String> basePackages = new ArrayList<>();\n        basePackages.addAll(Arrays.stream(annoAttrs.getStringArray(\"value\")).filter(StringUtils::hasText)\n                .collect(Collectors.toList()));\n        basePackages.addAll(Arrays.stream(annoAttrs.getStringArray(\"basePackages\")).filter(StringUtils::hasText)\n                .collect(Collectors.toList()));\n        factory.addConstructorArgValue(basePackages);\n        registry.registerBeanDefinition(generateBaseBeanName(annoMeta), factory.getBeanDefinition());\n    }\n    \n    private static String generateBaseBeanName(final AnnotationMetadata importingClassMetadata) {\n        return importingClassMetadata.getClassName() + \"#\" + ElasticJobScanRegistrar.class.getSimpleName();\n    }\n}\n"
  },
  {
    "path": "spring/core/src/main/java/org/apache/shardingsphere/elasticjob/spring/core/scanner/JobScannerConfiguration.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.core.scanner;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;\nimport org.springframework.util.Assert;\n\n/**\n * BeanDefinitionRegistryPostProcessor that searches recursively starting from a base package for interfaces.\n *\n */\n@Getter\n@RequiredArgsConstructor\npublic class JobScannerConfiguration implements BeanDefinitionRegistryPostProcessor, InitializingBean {\n    \n    private final String[] basePackages;\n    \n    @Override\n    public void afterPropertiesSet() {\n        Assert.notNull(this.basePackages, \"Property 'basePackage' is required\");\n    }\n    \n    @Override\n    public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {\n        // left intentionally blank\n    }\n    \n    @Override\n    public void postProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry) throws BeansException {\n        ClassPathJobScanner classPathJobScanner = new ClassPathJobScanner(registry);\n        classPathJobScanner.scan(basePackages);\n    }\n    \n}\n"
  },
  {
    "path": "spring/core/src/main/java/org/apache/shardingsphere/elasticjob/spring/core/setup/SpringProxyJobClassNameProvider.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.core.setup;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.setup.JobClassNameProvider;\nimport org.apache.shardingsphere.elasticjob.spring.core.util.AopTargetUtils;\nimport org.springframework.aop.support.AopUtils;\n\n/**\n * Spring job class name provider.\n * \n * <p>\n * Consider the proxy object that generated by cglib or jdk dynamic proxy.\n * </p>\n */\n@Slf4j\npublic final class SpringProxyJobClassNameProvider implements JobClassNameProvider {\n    \n    private static final String LAMBDA_CHARACTERISTICS = \"$$Lambda\";\n    \n    public SpringProxyJobClassNameProvider() {\n        log.info(\"create SpringProxyJobClassNameProvider\");\n    }\n    \n    @Override\n    public String getJobClassName(final ElasticJob elasticJob) {\n        if (!AopUtils.isAopProxy(elasticJob)) {\n            return getJobClassName(elasticJob.getClass());\n        }\n        return getJobClassName(AopTargetUtils.getTarget(elasticJob).getClass());\n    }\n    \n    private String getJobClassName(final Class<?> elasticJobClass) {\n        String elasticJobClassName = elasticJobClass.getName();\n        return isLambdaClass(elasticJobClass) ? trimLambdaClassSuffix(elasticJobClassName) : elasticJobClassName;\n    }\n    \n    private boolean isLambdaClass(final Class<?> elasticJobClass) {\n        return elasticJobClass.isSynthetic() && elasticJobClass.getSimpleName().contains(LAMBDA_CHARACTERISTICS);\n    }\n    \n    private String trimLambdaClassSuffix(final String className) {\n        return className.substring(0, className.lastIndexOf(LAMBDA_CHARACTERISTICS) + LAMBDA_CHARACTERISTICS.length());\n    }\n}\n"
  },
  {
    "path": "spring/core/src/main/java/org/apache/shardingsphere/elasticjob/spring/core/util/AopTargetUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.core.util;\n\nimport java.lang.reflect.Field;\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.exception.JobSystemException;\nimport org.springframework.aop.framework.AdvisedSupport;\nimport org.springframework.aop.support.AopUtils;\n\n/**\n * Aop target Utility.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class AopTargetUtils {\n    \n    /**\n     * Get target object.\n     * \n     * @param proxy proxy object\n     * @return target object\n     */\n    public static Object getTarget(final Object proxy) {\n        if (!AopUtils.isAopProxy(proxy)) {\n            return proxy;\n        }\n        if (AopUtils.isJdkDynamicProxy(proxy)) {\n            return getProxyTargetObject(proxy, \"h\");\n        } else {\n            return getProxyTargetObject(proxy, \"CGLIB$CALLBACK_0\");\n        }\n    }\n    \n    private static Object getProxyTargetObject(final Object proxy, final String proxyType) {\n        Field h;\n        try {\n            h = proxy.getClass().getSuperclass().getDeclaredField(proxyType);\n        } catch (final NoSuchFieldException ex) {\n            return getProxyTargetObjectForCglibAndSpring4(proxy);\n        }\n        h.setAccessible(true);\n        try {\n            return getTargetObject(h.get(proxy));\n        } catch (final IllegalAccessException ex) {\n            throw new JobSystemException(ex);\n        }\n    }\n    \n    private static Object getProxyTargetObjectForCglibAndSpring4(final Object proxy) {\n        Field h;\n        try {\n            h = proxy.getClass().getDeclaredField(\"CGLIB$CALLBACK_0\");\n            h.setAccessible(true);\n            Object dynamicAdvisedInterceptor = h.get(proxy);\n            Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField(\"advised\");\n            advised.setAccessible(true);\n            return ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            throw new JobSystemException(ex);\n        }\n    }\n    \n    private static Object getTargetObject(final Object object) {\n        try {\n            Field advised = object.getClass().getDeclaredField(\"advised\");\n            advised.setAccessible(true);\n            return ((AdvisedSupport) advised.get(object)).getTargetSource().getTarget();\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            throw new JobSystemException(ex);\n        }\n    }\n}\n"
  },
  {
    "path": "spring/core/src/main/resources/META-INF/services/org.apache.shardingsphere.elasticjob.kernel.internal.setup.JobClassNameProvider",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.spring.core.setup.SpringProxyJobClassNameProvider\n"
  },
  {
    "path": "spring/core/src/test/java/org/apache/shardingsphere/elasticjob/spring/core/setup/JobClassNameProviderFactoryTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.core.setup;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.setup.JobClassNameProviderFactory;\nimport org.junit.jupiter.api.Test;\n\nimport static org.hamcrest.CoreMatchers.instanceOf;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\nclass JobClassNameProviderFactoryTest {\n    \n    @Test\n    void assertGetStrategy() {\n        assertThat(JobClassNameProviderFactory.getProvider(), instanceOf(SpringProxyJobClassNameProvider.class));\n    }\n}\n"
  },
  {
    "path": "spring/core/src/test/java/org/apache/shardingsphere/elasticjob/spring/core/util/AopTargetUtilsTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.core.util;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.junit.jupiter.api.Test;\nimport org.springframework.aop.framework.ProxyFactory;\nimport org.springframework.aop.support.AopUtils;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertFalse;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass AopTargetUtilsTest {\n    \n    @Test\n    void assertJdkDynamicProxyForGetTarget() {\n        ElasticJob target = new TargetJob();\n        ProxyFactory pf = new ProxyFactory(target);\n        pf.addInterface(ElasticJob.class);\n        ElasticJob proxy = (ElasticJob) pf.getProxy();\n        assertTrue(AopUtils.isJdkDynamicProxy(proxy));\n        assertThat(AopTargetUtils.getTarget(proxy), is(target));\n    }\n    \n    @Test\n    void assertCglibProxyForGetTarget() {\n        ElasticJob target = new TargetJob();\n        ProxyFactory pf = new ProxyFactory(target);\n        pf.setProxyTargetClass(true);\n        ElasticJob proxy = (ElasticJob) pf.getProxy();\n        assertTrue(AopUtils.isCglibProxy(proxy));\n        assertThat(AopTargetUtils.getTarget(proxy), is(target));\n    }\n    \n    @Test\n    void assertNoneProxyForGetTarget() {\n        ElasticJob proxy = new TargetJob();\n        assertFalse(AopUtils.isAopProxy(proxy));\n        assertThat(AopTargetUtils.getTarget(proxy), is(proxy));\n    }\n}\n"
  },
  {
    "path": "spring/core/src/test/java/org/apache/shardingsphere/elasticjob/spring/core/util/TargetJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.core.util;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\npublic class TargetJob implements ElasticJob {\n    \n    /**\n     * Mocker object for AopTargetUtilsTest.\n     *\n     * @param shardingContext shardingContext\n     */\n    public void execute(final ShardingContext shardingContext) {\n    }\n}\n"
  },
  {
    "path": "spring/core/src/test/resources/META-INF/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <level value=\"WARN\" />\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.zookeeper\" level=\"ERROR\" />\n    <logger name=\"org.apache.curator\" level=\"ERROR\" />\n    <logger name=\"org.apache.shardingsphere.elasticjob.kernel.internal.executor.error.handler.type.LogJobErrorHandler\" level=\"OFF\" />\n</configuration>\n"
  },
  {
    "path": "spring/namespace/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-spring</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-spring-namespace</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-spring-core</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-email</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-wechat</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-error-handler-dingtalk</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>provided</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-test-util</artifactId>\n            <version>${project.parent.version}</version>\n            <scope>test</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context-support</artifactId>\n            <scope>provided</scope>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.aspectj</groupId>\n            <artifactId>aspectjweaver</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.awaitility</groupId>\n            <artifactId>awaitility</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/ElasticJobNamespaceHandler.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace;\n\nimport org.apache.shardingsphere.elasticjob.spring.namespace.scanner.parser.JobScannerBeanDefinitionParser;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.job.parser.JobBeanDefinitionParser;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.reg.parser.ZookeeperBeanDefinitionParser;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.snapshot.parser.SnapshotBeanDefinitionParser;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.tracing.parser.TracingBeanDefinitionParser;\nimport org.springframework.beans.factory.xml.NamespaceHandlerSupport;\n\n/**\n * Job handler for spring namespace.\n */\npublic final class ElasticJobNamespaceHandler extends NamespaceHandlerSupport {\n    \n    @Override\n    public void init() {\n        registerBeanDefinitionParser(\"job\", new JobBeanDefinitionParser());\n        registerBeanDefinitionParser(\"zookeeper\", new ZookeeperBeanDefinitionParser());\n        registerBeanDefinitionParser(\"snapshot\", new SnapshotBeanDefinitionParser());\n        registerBeanDefinitionParser(\"rdb-tracing\", new TracingBeanDefinitionParser());\n        registerBeanDefinitionParser(\"job-scanner\", new JobScannerBeanDefinitionParser());\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/parser/JobBeanDefinitionParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job.parser;\n\nimport com.google.common.base.Strings;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.job.tag.JobBeanDefinitionTag;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.support.ManagedList;\nimport org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;\nimport org.springframework.beans.factory.xml.ParserContext;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.xml.DomUtils;\nimport org.w3c.dom.Element;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Properties;\n\n/**\n * Job bean definition parser.\n */\npublic final class JobBeanDefinitionParser extends AbstractBeanDefinitionParser {\n    \n    @Override\n    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext) {\n        BeanDefinitionBuilder factory;\n        if (Strings.isNullOrEmpty(element.getAttribute(JobBeanDefinitionTag.CRON_ATTRIBUTE))) {\n            factory = BeanDefinitionBuilder.rootBeanDefinition(OneOffJobBootstrap.class);\n        } else {\n            factory = BeanDefinitionBuilder.rootBeanDefinition(ScheduleJobBootstrap.class);\n            factory.setInitMethodName(\"schedule\");\n        }\n        factory.addConstructorArgReference(element.getAttribute(JobBeanDefinitionTag.REGISTRY_CENTER_REF_ATTRIBUTE));\n        String jobType = element.getAttribute(JobBeanDefinitionTag.JOB_TYPE_ATTRIBUTE);\n        if (!Strings.isNullOrEmpty(jobType)) {\n            factory.addConstructorArgValue(jobType);\n        } else {\n            factory.addConstructorArgReference(element.getAttribute(JobBeanDefinitionTag.JOB_REF_ATTRIBUTE));\n        }\n        factory.addConstructorArgValue(createJobConfigurationBeanDefinition(element, parserContext));\n        return factory.getBeanDefinition();\n    }\n    \n    private BeanDefinition createJobConfigurationBeanDefinition(final Element element, final ParserContext parserContext) {\n        BeanDefinitionBuilder result = BeanDefinitionBuilder.rootBeanDefinition(JobConfiguration.class);\n        result.addConstructorArgValue(element.getAttribute(ID_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.CRON_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.TIME_ZONE_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.SHARDING_TOTAL_COUNT_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.SHARDING_ITEM_PARAMETERS_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.JOB_PARAMETER_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.MONITOR_EXECUTION_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.FAILOVER_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.MISFIRE_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.MAX_TIME_DIFF_SECONDS_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.RECONCILE_INTERVAL_MINUTES));\n        result.addConstructorArgValue(\n                element.hasAttribute(JobBeanDefinitionTag.JOB_SHARDING_STRATEGY_TYPE_ATTRIBUTE) ? element.getAttribute(JobBeanDefinitionTag.JOB_SHARDING_STRATEGY_TYPE_ATTRIBUTE) : null);\n        result.addConstructorArgValue(\n                element.hasAttribute(JobBeanDefinitionTag.JOB_EXECUTOR_SERVICE_HANDLER_TYPE_ATTRIBUTE)\n                        ? element.getAttribute(JobBeanDefinitionTag.JOB_EXECUTOR_SERVICE_HANDLER_TYPE_ATTRIBUTE)\n                        : null);\n        result.addConstructorArgValue(\n                element.hasAttribute(JobBeanDefinitionTag.JOB_ERROR_HANDLER_TYPE_ATTRIBUTE) ? element.getAttribute(JobBeanDefinitionTag.JOB_ERROR_HANDLER_TYPE_ATTRIBUTE) : null);\n        if (ObjectUtils.isEmpty(element.getAttribute(JobBeanDefinitionTag.JOB_LISTENER_TYPES_ATTRIBUTE).trim())) {\n            result.addConstructorArgValue(Collections.emptyList());\n        } else {\n            result.addConstructorArgValue(Arrays.asList(element.getAttribute(JobBeanDefinitionTag.JOB_LISTENER_TYPES_ATTRIBUTE).split(\",\")));\n        }\n        result.addConstructorArgValue(parseExtraConfigs(new String[]{JobBeanDefinitionTag.TRACING_REF_ATTRIBUTE},\n                element, parserContext));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.DESCRIPTION_ATTRIBUTE));\n        result.addConstructorArgValue(parsePropsElement(element, parserContext));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.DISABLED_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.OVERWRITE_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.LABEL_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(JobBeanDefinitionTag.STATIC_SHARDING_ATTRIBUTE));\n        return result.getBeanDefinition();\n    }\n    \n    private Collection<BeanDefinition> parseExtraConfigs(final String[] extraConfigRefs, final Element element, final ParserContext parserContext) {\n        Collection<BeanDefinition> result = new ManagedList<>(extraConfigRefs.length);\n        for (String each : extraConfigRefs) {\n            String attribute = element.getAttribute(each);\n            if (!Strings.isNullOrEmpty(attribute)) {\n                result.add(parserContext.getRegistry().getBeanDefinition(attribute));\n            }\n        }\n        return result;\n    }\n    \n    private Properties parsePropsElement(final Element element, final ParserContext parserContext) {\n        Element propsElement = DomUtils.getChildElementByTagName(element, JobBeanDefinitionTag.PROPS_TAG);\n        return null == propsElement ? new Properties() : parserContext.getDelegate().parsePropsElement(propsElement);\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/tag/JobBeanDefinitionTag.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job.tag;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n/**\n * Job bean definition tag.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class JobBeanDefinitionTag {\n    \n    public static final String JOB_REF_ATTRIBUTE = \"job-ref\";\n    \n    public static final String JOB_TYPE_ATTRIBUTE = \"job-type\";\n    \n    public static final String REGISTRY_CENTER_REF_ATTRIBUTE = \"registry-center-ref\";\n    \n    public static final String TRACING_REF_ATTRIBUTE = \"tracing-ref\";\n    \n    public static final String CRON_ATTRIBUTE = \"cron\";\n    \n    public static final String TIME_ZONE_ATTRIBUTE = \"time-zone\";\n    \n    public static final String SHARDING_TOTAL_COUNT_ATTRIBUTE = \"sharding-total-count\";\n    \n    public static final String SHARDING_ITEM_PARAMETERS_ATTRIBUTE = \"sharding-item-parameters\";\n    \n    public static final String JOB_PARAMETER_ATTRIBUTE = \"job-parameter\";\n    \n    public static final String MONITOR_EXECUTION_ATTRIBUTE = \"monitor-execution\";\n    \n    public static final String FAILOVER_ATTRIBUTE = \"failover\";\n    \n    public static final String MISFIRE_ATTRIBUTE = \"misfire\";\n    \n    public static final String MAX_TIME_DIFF_SECONDS_ATTRIBUTE = \"max-time-diff-seconds\";\n    \n    public static final String RECONCILE_INTERVAL_MINUTES = \"reconcile-interval-minutes\";\n    \n    public static final String JOB_SHARDING_STRATEGY_TYPE_ATTRIBUTE = \"job-sharding-strategy-type\";\n    \n    public static final String JOB_EXECUTOR_SERVICE_HANDLER_TYPE_ATTRIBUTE = \"job-executor-service-handler-type\";\n    \n    public static final String JOB_ERROR_HANDLER_TYPE_ATTRIBUTE = \"job-error-handler-type\";\n    \n    public static final String JOB_LISTENER_TYPES_ATTRIBUTE = \"job-listener-types\";\n    \n    public static final String DESCRIPTION_ATTRIBUTE = \"description\";\n    \n    public static final String PROPS_TAG = \"props\";\n    \n    public static final String DISABLED_ATTRIBUTE = \"disabled\";\n    \n    public static final String OVERWRITE_ATTRIBUTE = \"overwrite\";\n    \n    public static final String LABEL_ATTRIBUTE = \"label\";\n    \n    public static final String STATIC_SHARDING_ATTRIBUTE = \"static-sharding\";\n}\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/reg/parser/ZookeeperBeanDefinitionParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.reg.parser;\n\nimport com.google.common.base.Strings;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.reg.tag.ZookeeperBeanDefinitionTag;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;\nimport org.springframework.beans.factory.xml.ParserContext;\nimport org.w3c.dom.Element;\n\n/**\n * Bean definition parser for ZooKeeper.\n */\npublic final class ZookeeperBeanDefinitionParser extends AbstractBeanDefinitionParser {\n    \n    @Override\n    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext) {\n        BeanDefinitionBuilder result = BeanDefinitionBuilder.rootBeanDefinition(ZookeeperRegistryCenter.class);\n        result.addConstructorArgValue(buildZookeeperConfigurationBeanDefinition(element));\n        result.setInitMethodName(\"init\");\n        result.setDestroyMethodName(\"close\");\n        return result.getBeanDefinition();\n    }\n    \n    private AbstractBeanDefinition buildZookeeperConfigurationBeanDefinition(final Element element) {\n        BeanDefinitionBuilder config = BeanDefinitionBuilder.rootBeanDefinition(ZookeeperConfiguration.class);\n        config.addConstructorArgValue(element.getAttribute(ZookeeperBeanDefinitionTag.SERVER_LISTS_ATTRIBUTE));\n        config.addConstructorArgValue(element.getAttribute(ZookeeperBeanDefinitionTag.NAMESPACE_ATTRIBUTE));\n        addPropertyValueIfNotEmpty(ZookeeperBeanDefinitionTag.BASE_SLEEP_TIME_MILLISECONDS_ATTRIBUTE, \"baseSleepTimeMilliseconds\", element, config);\n        addPropertyValueIfNotEmpty(ZookeeperBeanDefinitionTag.MAX_SLEEP_TIME_MILLISECONDS_ATTRIBUTE, \"maxSleepTimeMilliseconds\", element, config);\n        addPropertyValueIfNotEmpty(ZookeeperBeanDefinitionTag.MAX_RETRIES_ATTRIBUTE, \"maxRetries\", element, config);\n        addPropertyValueIfNotEmpty(ZookeeperBeanDefinitionTag.SESSION_TIMEOUT_MILLISECONDS_ATTRIBUTE, \"sessionTimeoutMilliseconds\", element, config);\n        addPropertyValueIfNotEmpty(ZookeeperBeanDefinitionTag.CONNECTION_TIMEOUT_MILLISECONDS_ATTRIBUTE, \"connectionTimeoutMilliseconds\", element, config);\n        addPropertyValueIfNotEmpty(ZookeeperBeanDefinitionTag.DIGEST_ATTRIBUTE, \"digest\", element, config);\n        return config.getBeanDefinition();\n    }\n    \n    private void addPropertyValueIfNotEmpty(final String attributeName, final String propertyName, final Element element, final BeanDefinitionBuilder factory) {\n        String attributeValue = element.getAttribute(attributeName);\n        if (!Strings.isNullOrEmpty(attributeValue)) {\n            factory.addPropertyValue(propertyName, attributeValue);\n        }\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/reg/tag/ZookeeperBeanDefinitionTag.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.reg.tag;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n/**\n * Zookeeper bean definition tag.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class ZookeeperBeanDefinitionTag {\n    \n    public static final String SERVER_LISTS_ATTRIBUTE = \"server-lists\";\n    \n    public static final String NAMESPACE_ATTRIBUTE = \"namespace\";\n    \n    public static final String BASE_SLEEP_TIME_MILLISECONDS_ATTRIBUTE = \"base-sleep-time-milliseconds\";\n    \n    public static final String MAX_SLEEP_TIME_MILLISECONDS_ATTRIBUTE = \"max-sleep-time-milliseconds\";\n    \n    public static final String MAX_RETRIES_ATTRIBUTE = \"max-retries\";\n    \n    public static final String SESSION_TIMEOUT_MILLISECONDS_ATTRIBUTE = \"session-timeout-milliseconds\";\n    \n    public static final String CONNECTION_TIMEOUT_MILLISECONDS_ATTRIBUTE = \"connection-timeout-milliseconds\";\n    \n    public static final String DIGEST_ATTRIBUTE = \"digest\";\n}\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/scanner/parser/JobScannerBeanDefinitionParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.scanner.parser;\n\nimport org.apache.shardingsphere.elasticjob.spring.core.scanner.JobScannerConfiguration;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.scanner.tag.JobScannerBeanDefinitionTag;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;\nimport org.springframework.beans.factory.xml.ParserContext;\nimport org.w3c.dom.Element;\n\n/**\n * Job scanner bean definition parser.\n */\npublic final class JobScannerBeanDefinitionParser extends AbstractBeanDefinitionParser {\n    \n    @Override\n    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext) {\n        BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(JobScannerConfiguration.class);\n        String attribute = element.getAttribute(JobScannerBeanDefinitionTag.BASE_PACKAGE);\n        factory.addConstructorArgValue(attribute);\n        return factory.getBeanDefinition();\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/scanner/tag/JobScannerBeanDefinitionTag.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.scanner.tag;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n/**\n * Job scanner bean definition tag.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic class JobScannerBeanDefinitionTag {\n    \n    public static final String BASE_PACKAGE = \"base-package\";\n}\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/snapshot/parser/SnapshotBeanDefinitionParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.snapshot.parser;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.snapshot.tag.SnapshotBeanDefinitionTag;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;\nimport org.springframework.beans.factory.xml.ParserContext;\nimport org.w3c.dom.Element;\n\n/**\n * Snapshot bean definition parser.\n */\npublic final class SnapshotBeanDefinitionParser extends AbstractBeanDefinitionParser {\n    \n    @Override\n    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext) {\n        BeanDefinitionBuilder result = BeanDefinitionBuilder.rootBeanDefinition(SnapshotService.class);\n        result.addConstructorArgReference(element.getAttribute(SnapshotBeanDefinitionTag.REGISTRY_CENTER_REF_ATTRIBUTE));\n        result.addConstructorArgValue(element.getAttribute(SnapshotBeanDefinitionTag.DUMP_PORT_ATTRIBUTE));\n        result.setInitMethodName(\"listen\");\n        result.setDestroyMethodName(\"close\");\n        return result.getBeanDefinition();\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/snapshot/tag/SnapshotBeanDefinitionTag.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.snapshot.tag;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n/**\n * Snapshot bean definition tag.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class SnapshotBeanDefinitionTag {\n    \n    public static final String REGISTRY_CENTER_REF_ATTRIBUTE = \"registry-center-ref\";\n    \n    public static final String DUMP_PORT_ATTRIBUTE = \"dump-port\";\n}\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/tracing/parser/TracingBeanDefinitionParser.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.tracing.parser;\n\nimport org.apache.shardingsphere.elasticjob.spring.namespace.tracing.tag.TracingBeanDefinitionTag;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.springframework.beans.factory.support.AbstractBeanDefinition;\nimport org.springframework.beans.factory.support.BeanDefinitionBuilder;\nimport org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;\nimport org.springframework.beans.factory.xml.ParserContext;\nimport org.w3c.dom.Element;\n\n/**\n * Tracing bean definition parser.\n */\npublic final class TracingBeanDefinitionParser extends AbstractBeanDefinitionParser {\n    \n    @Override\n    protected AbstractBeanDefinition parseInternal(final Element element, final ParserContext parserContext) {\n        BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(TracingConfiguration.class);\n        factory.addConstructorArgValue(\"RDB\");\n        factory.addConstructorArgReference(element.getAttribute(TracingBeanDefinitionTag.DATA_SOURCE_REF_ATTRIBUTE));\n        return factory.getBeanDefinition();\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/main/java/org/apache/shardingsphere/elasticjob/spring/namespace/tracing/tag/TracingBeanDefinitionTag.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.tracing.tag;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n/**\n * Tracing bean definition tag.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class TracingBeanDefinitionTag {\n    \n    public static final String DATA_SOURCE_REF_ATTRIBUTE = \"data-source-ref\";\n}\n"
  },
  {
    "path": "spring/namespace/src/main/resources/META-INF/namespace/elasticjob.xsd",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<xsd:schema xmlns=\"http://shardingsphere.apache.org/schema/elasticjob\"\n            xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"\n            xmlns:beans=\"http://www.springframework.org/schema/beans\"\n            targetNamespace=\"http://shardingsphere.apache.org/schema/elasticjob\"\n            elementFormDefault=\"qualified\">\n    <xsd:import namespace=\"http://www.springframework.org/schema/beans\"\n                schemaLocation=\"http://www.springframework.org/schema/beans/spring-beans.xsd\"/>\n\n    <xsd:element name=\"job-scanner\">\n        <xsd:complexType>\n            <xsd:complexContent>\n                <xsd:extension base=\"beans:identifiedType\">\n                    <xsd:attribute name=\"base-package\" type=\"xsd:string\" use=\"required\"/>\n                </xsd:extension>\n            </xsd:complexContent>\n        </xsd:complexType>\n    </xsd:element>\n\n    <xsd:element name=\"job\">\n        <xsd:complexType>\n            <xsd:complexContent>\n                <xsd:extension base=\"beans:identifiedType\">\n                    <xsd:all>\n                        <xsd:element ref=\"beans:props\" minOccurs=\"0\" />\n                    </xsd:all>\n                    <xsd:attribute name=\"job-ref\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"job-type\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"registry-center-ref\" type=\"xsd:string\" use=\"required\" />\n                    <xsd:attribute name=\"sharding-total-count\" type=\"xsd:string\" use=\"required\" />\n                    <xsd:attribute name=\"cron\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"time-zone\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"sharding-item-parameters\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"job-parameter\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"monitor-execution\" type=\"xsd:string\" default=\"true\" />\n                    <xsd:attribute name=\"max-time-diff-seconds\" type=\"xsd:string\" default=\"-1\" />\n                    <xsd:attribute name=\"failover\" type=\"xsd:string\" default=\"false\" />\n                    <xsd:attribute name=\"reconcile-interval-minutes\" type=\"xsd:string\" default=\"10\" />\n                    <xsd:attribute name=\"misfire\" type=\"xsd:string\" default=\"true\" />\n                    <xsd:attribute name=\"job-sharding-strategy-type\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"job-executor-service-handler-type\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"job-error-handler-type\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"job-listener-types\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"tracing-ref\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"description\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"disabled\" type=\"xsd:string\" default=\"false\" />\n                    <xsd:attribute name=\"overwrite\" type=\"xsd:string\" default=\"false\" />\n                    <xsd:attribute name=\"label\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"static-sharding\" type=\"xsd:string\" default=\"false\" />\n                </xsd:extension>\n            </xsd:complexContent>\n        </xsd:complexType>\n    </xsd:element>\n\n    <xsd:element name=\"zookeeper\">\n        <xsd:complexType>\n            <xsd:complexContent>\n                <xsd:extension base=\"beans:identifiedType\">\n                    <xsd:attribute name=\"server-lists\" type=\"xsd:string\" use=\"required\" />\n                    <xsd:attribute name=\"namespace\" type=\"xsd:string\" use=\"required\" />\n                    <xsd:attribute name=\"base-sleep-time-milliseconds\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"max-sleep-time-milliseconds\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"max-retries\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"session-timeout-milliseconds\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"connection-timeout-milliseconds\" type=\"xsd:string\" />\n                    <xsd:attribute name=\"digest\" type=\"xsd:string\" />\n                </xsd:extension>\n            </xsd:complexContent>\n        </xsd:complexType>\n    </xsd:element>\n\n    <xsd:element name=\"rdb-tracing\">\n        <xsd:complexType>\n            <xsd:complexContent>\n                <xsd:extension base=\"beans:identifiedType\">\n                    <xsd:attribute name=\"data-source-ref\" type=\"xsd:string\" use=\"required\" />\n                </xsd:extension>\n            </xsd:complexContent>\n        </xsd:complexType>\n    </xsd:element>\n\n    <xsd:element name=\"snapshot\">\n        <xsd:complexType>\n            <xsd:complexContent>\n                <xsd:extension base=\"beans:identifiedType\">\n                    <xsd:attribute name=\"registry-center-ref\" type=\"xsd:string\" use=\"required\" />\n                    <xsd:attribute name=\"dump-port\" type=\"xsd:string\" use=\"required\" />\n                </xsd:extension>\n            </xsd:complexContent>\n        </xsd:complexType>\n    </xsd:element>\n</xsd:schema>\n"
  },
  {
    "path": "spring/namespace/src/main/resources/META-INF/spring.handlers",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nhttp\\://shardingsphere.apache.org/schema/elasticjob=org.apache.shardingsphere.elasticjob.spring.namespace.ElasticJobNamespaceHandler\n"
  },
  {
    "path": "spring/namespace/src/main/resources/META-INF/spring.schemas",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nhttp\\://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd=META-INF/namespace/elasticjob.xsd\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/aspect/SimpleAspect.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.aspect;\n\nimport org.aspectj.lang.JoinPoint;\nimport org.springframework.stereotype.Component;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Before;\nimport org.aspectj.lang.annotation.Pointcut;\n\n@Component\n@Aspect\npublic class SimpleAspect {\n    \n    /**\n     * Aspect.\n     */\n    @Pointcut(\"execution(* org.apache.shardingsphere.elasticjob.spring.fixture..*(..))\")\n    public void aspect() {\n    }\n    \n    /**\n     * Before operator.\n     * @param joinPoint joinPoint\n     */\n    @Before(\"aspect()\")\n    public void before(final JoinPoint joinPoint) {\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/job/DataflowElasticJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.job;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class DataflowElasticJob implements DataflowJob<String> {\n    \n    @Getter\n    private static volatile boolean completed;\n    \n    @Override\n    public List<String> fetchData(final ShardingContext shardingContext) {\n        if (completed) {\n            return Collections.emptyList();\n        }\n        return Collections.singletonList(\"data\");\n    }\n    \n    @Override\n    public void processData(final ShardingContext shardingContext, final List<String> data) {\n        completed = true;\n    }\n    \n    /**\n     * Set completed to false.\n     */\n    public static void reset() {\n        completed = false;\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/job/FooSimpleElasticJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.job;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\n\npublic class FooSimpleElasticJob implements SimpleJob {\n    \n    @Getter\n    private static volatile boolean completed;\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        completed = true;\n    }\n    \n    /**\n     * Set completed to false.\n     */\n    public static void reset() {\n        completed = false;\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/job/annotation/AnnotationSimpleJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.annotation;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobConfiguration;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobProp;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\n\n@Getter\n@ElasticJobConfiguration(\n        jobName = \"simpleJob\",\n        registryCenter = \"regCenter\",\n        description = \"desc\",\n        shardingTotalCount = 3,\n        shardingItemParameters = \"0=a,1=b,2=c\",\n        cron = \"*/1 * * * * ?\",\n        props = {\n                @ElasticJobProp(key = \"print.title\", value = \"test title\"),\n                @ElasticJobProp(key = \"print.content\", value = \"test content\")\n        })\npublic final class AnnotationSimpleJob implements SimpleJob {\n    \n    @Getter\n    private static volatile boolean completed;\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        completed = true;\n    }\n    \n    /**\n     * Set completed to false.\n     */\n    public static void reset() {\n        completed = false;\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/job/ref/RefFooDataflowElasticJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.ref;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.fixture.service.FooService;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class RefFooDataflowElasticJob implements DataflowJob<String> {\n    \n    @Getter\n    private static volatile boolean completed;\n    \n    @Getter\n    @Setter\n    private FooService fooService;\n    \n    @Override\n    public List<String> fetchData(final ShardingContext shardingContext) {\n        if (completed) {\n            return Collections.emptyList();\n        }\n        fooService.foo();\n        return Collections.singletonList(\"data\");\n    }\n    \n    @Override\n    public void processData(final ShardingContext shardingContext, final List<String> data) {\n        completed = true;\n    }\n    \n    /**\n     * Set completed to false.\n     */\n    public static void reset() {\n        completed = false;\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/job/ref/RefFooSimpleElasticJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.ref;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.fixture.service.FooService;\n\npublic class RefFooSimpleElasticJob implements SimpleJob {\n    \n    @Getter\n    private static volatile boolean completed;\n    \n    @Getter\n    @Setter\n    private FooService fooService;\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        fooService.foo();\n        completed = true;\n    }\n    \n    /**\n     * Set completed to false.\n     */\n    public static void reset() {\n        completed = false;\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/listener/SimpleCglibListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class SimpleCglibListener implements ElasticJobListener {\n    \n    @Override\n    public void beforeJobExecuted(final ShardingContexts shardingContexts) {\n        assertThat(shardingContexts.getJobName(), is(\"simpleElasticJob_namespace_listener_cglib\"));\n    }\n    \n    @Override\n    public void afterJobExecuted(final ShardingContexts shardingContexts) {\n        assertThat(shardingContexts.getJobName(), is(\"simpleElasticJob_namespace_listener_cglib\"));\n    }\n    \n    @Override\n    public String getType() {\n        return \"simpleCglibListener\";\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/listener/SimpleJdkDynamicProxyListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class SimpleJdkDynamicProxyListener implements ElasticJobListener {\n    \n    @Override\n    public void beforeJobExecuted(final ShardingContexts shardingContexts) {\n        assertThat(shardingContexts.getJobName(), is(\"simpleElasticJob_namespace_listener_jdk_proxy\"));\n    }\n    \n    @Override\n    public void afterJobExecuted(final ShardingContexts shardingContexts) {\n        assertThat(shardingContexts.getJobName(), is(\"simpleElasticJob_namespace_listener_jdk_proxy\"));\n    }\n    \n    @Override\n    public String getType() {\n        return \"simpleJdkDynamicProxyListener\";\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/listener/SimpleListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class SimpleListener implements ElasticJobListener {\n    \n    @Override\n    public void beforeJobExecuted(final ShardingContexts shardingContexts) {\n        assertThat(shardingContexts.getJobName(), is(\"simpleElasticJob_namespace_listener\"));\n    }\n    \n    @Override\n    public void afterJobExecuted(final ShardingContexts shardingContexts) {\n        assertThat(shardingContexts.getJobName(), is(\"simpleElasticJob_namespace_listener\"));\n    }\n    \n    @Override\n    public String getType() {\n        return \"simpleListener\";\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/listener/SimpleOnceListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.listener;\n\nimport org.apache.shardingsphere.elasticjob.kernel.listener.AbstractDistributeOnceElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class SimpleOnceListener extends AbstractDistributeOnceElasticJobListener {\n    \n    private final long startedTimeoutMilliseconds;\n    \n    private final long completedTimeoutMilliseconds;\n    \n    public SimpleOnceListener() {\n        super(10000L, 20000L);\n        startedTimeoutMilliseconds = 10000L;\n        completedTimeoutMilliseconds = 20000L;\n    }\n    \n    @Override\n    public void doBeforeJobExecutedAtLastStarted(final ShardingContexts shardingContexts) {\n        assertThat(startedTimeoutMilliseconds, is(10000L));\n    }\n    \n    @Override\n    public void doAfterJobExecutedAtLastCompleted(final ShardingContexts shardingContexts) {\n        assertThat(completedTimeoutMilliseconds, is(20000L));\n    }\n    \n    @Override\n    public String getType() {\n        return \"simpleOnceListener\";\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/service/FooService.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.service;\n\npublic interface FooService {\n    \n    /**\n     * Execute foo.\n     *\n     * @return string\n     */\n    String foo();\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/fixture/service/FooServiceImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.fixture.service;\n\npublic class FooServiceImpl implements FooService {\n    \n    @Override\n    public String foo() {\n        return \"this is fooService.\";\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/AbstractJobSpringIntegrateTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.awaitility.Awaitility;\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.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n@ExtendWith(SpringExtension.class)\n@RequiredArgsConstructor\npublic abstract class AbstractJobSpringIntegrateTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer(3181);\n    \n    private final String simpleJobName;\n    \n    private final String throughputDataflowJobName;\n    \n    @Autowired\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @BeforeEach\n    @AfterEach\n    void reset() {\n        FooSimpleElasticJob.reset();\n        DataflowElasticJob.reset();\n    }\n    \n    @AfterEach\n    void tearDown() {\n        JobRegistry.getInstance().shutdown(simpleJobName);\n        JobRegistry.getInstance().shutdown(throughputDataflowJobName);\n    }\n    \n    @Test\n    void assertSpringJobBean() {\n        assertSimpleElasticJobBean();\n        assertThroughputDataflowElasticJobBean();\n    }\n    \n    private void assertSimpleElasticJobBean() {\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> assertThat(FooSimpleElasticJob.isCompleted(), is(true)));\n        assertTrue(FooSimpleElasticJob.isCompleted());\n        assertTrue(regCenter.isExisted(\"/\" + simpleJobName + \"/sharding\"));\n    }\n    \n    private void assertThroughputDataflowElasticJobBean() {\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> assertThat(DataflowElasticJob.isCompleted(), is(true)));\n        assertTrue(DataflowElasticJob.isCompleted());\n        assertTrue(regCenter.isExisted(\"/\" + throughputDataflowJobName + \"/sharding\"));\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/AbstractOneOffJobSpringIntegrateTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.awaitility.Awaitility;\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.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n@ExtendWith(SpringExtension.class)\n@RequiredArgsConstructor\npublic abstract class AbstractOneOffJobSpringIntegrateTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer(3181);\n    \n    private final String simpleJobName;\n    \n    private final String throughputDataflowJobName;\n    \n    @Autowired\n    private ApplicationContext applicationContext;\n    \n    @Autowired\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @BeforeEach\n    @AfterEach\n    void reset() {\n        FooSimpleElasticJob.reset();\n        DataflowElasticJob.reset();\n    }\n    \n    @AfterEach\n    void tearDown() {\n        JobRegistry.getInstance().shutdown(simpleJobName);\n        JobRegistry.getInstance().shutdown(throughputDataflowJobName);\n    }\n    \n    @Test\n    void assertSpringJobBean() {\n        assertSimpleElasticJobBean();\n        assertThroughputDataflowElasticJobBean();\n    }\n    \n    private void assertSimpleElasticJobBean() {\n        OneOffJobBootstrap bootstrap = applicationContext.getBean(simpleJobName, OneOffJobBootstrap.class);\n        bootstrap.execute();\n        Awaitility.await().atMost(5L, TimeUnit.MINUTES).untilAsserted(() -> assertThat(FooSimpleElasticJob.isCompleted(), is(true)));\n        assertTrue(FooSimpleElasticJob.isCompleted());\n        assertTrue(regCenter.isExisted(\"/\" + simpleJobName + \"/sharding\"));\n    }\n    \n    private void assertThroughputDataflowElasticJobBean() {\n        OneOffJobBootstrap bootstrap = applicationContext.getBean(throughputDataflowJobName, OneOffJobBootstrap.class);\n        bootstrap.execute();\n        Awaitility.await().atMost(5L, TimeUnit.MINUTES).untilAsserted(() -> assertThat(DataflowElasticJob.isCompleted(), is(true)));\n        assertTrue(DataflowElasticJob.isCompleted());\n        assertTrue(regCenter.isExisted(\"/\" + throughputDataflowJobName + \"/sharding\"));\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/JobSpringNamespaceWithEventTraceRdbTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/withEventTraceRdb.xml\")\nclass JobSpringNamespaceWithEventTraceRdbTest extends AbstractJobSpringIntegrateTest {\n    \n    JobSpringNamespaceWithEventTraceRdbTest() {\n        super(\"simpleElasticJob_namespace_event_trace_rdb\", \"dataflowElasticJob_namespace_event_trace_rdb\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/JobSpringNamespaceWithJobHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/withJobHandler.xml\")\nclass JobSpringNamespaceWithJobHandlerTest extends AbstractJobSpringIntegrateTest {\n    \n    JobSpringNamespaceWithJobHandlerTest() {\n        super(\"simpleElasticJob_namespace_job_handler\", \"dataflowElasticJob_namespace_job_handler\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/JobSpringNamespaceWithListenerAndCglibTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/withListenerAndCglib.xml\")\nclass JobSpringNamespaceWithListenerAndCglibTest extends AbstractJobSpringIntegrateTest {\n    \n    JobSpringNamespaceWithListenerAndCglibTest() {\n        super(\"simpleElasticJob_namespace_listener_cglib\", \"dataflowElasticJob_namespace_listener_cglib\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/JobSpringNamespaceWithListenerAndJdkDynamicProxyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/withListenerAndJdkDynamicProxy.xml\")\nclass JobSpringNamespaceWithListenerAndJdkDynamicProxyTest extends AbstractJobSpringIntegrateTest {\n    \n    JobSpringNamespaceWithListenerAndJdkDynamicProxyTest() {\n        super(\"simpleElasticJob_namespace_listener_jdk_proxy\", \"dataflowElasticJob_namespace_listener_jdk_proxy\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/JobSpringNamespaceWithListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/withListener.xml\")\nclass JobSpringNamespaceWithListenerTest extends AbstractJobSpringIntegrateTest {\n    \n    JobSpringNamespaceWithListenerTest() {\n        super(\"simpleElasticJob_namespace_listener\", \"dataflowElasticJob_namespace_listener\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/JobSpringNamespaceWithRefTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.ref.RefFooSimpleElasticJob;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.awaitility.Awaitility;\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.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(locations = \"classpath:META-INF/job/withJobRef.xml\")\nclass JobSpringNamespaceWithRefTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer(3181);\n    \n    private final String simpleJobName = \"simpleElasticJob_job_ref\";\n    \n    @Autowired\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @BeforeEach\n    @AfterEach\n    void reset() {\n        RefFooSimpleElasticJob.reset();\n    }\n    \n    @AfterEach\n    void tearDown() {\n        JobRegistry.getInstance().shutdown(simpleJobName);\n    }\n    \n    @Test\n    void assertSpringJobBean() {\n        assertSimpleElasticJobBean();\n    }\n    \n    private void assertSimpleElasticJobBean() {\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> assertThat(RefFooSimpleElasticJob.isCompleted(), is(true)));\n        assertTrue(RefFooSimpleElasticJob.isCompleted());\n        assertTrue(regCenter.isExisted(\"/\" + simpleJobName + \"/sharding\"));\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/JobSpringNamespaceWithTypeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.quartz.Scheduler;\nimport org.quartz.SchedulerException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * todo There is no `echo` program on Windows 11 cmd. Waiting for a fix.\n */\n@EnabledOnOs(OS.LINUX)\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(locations = \"classpath:META-INF/job/withJobType.xml\")\nclass JobSpringNamespaceWithTypeTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer(3181);\n    \n    private final String scriptJobName = \"scriptElasticJob_job_type\";\n    \n    @Autowired\n    private CoordinatorRegistryCenter regCenter;\n    \n    private Scheduler scheduler;\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @AfterEach\n    void tearDown() {\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).until(() -> scheduler.getCurrentlyExecutingJobs().isEmpty());\n        JobRegistry.getInstance().getJobScheduleController(scriptJobName).shutdown();\n    }\n    \n    @Test\n    void jobScriptWithJobTypeTest() throws SchedulerException {\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).until(() -> regCenter.isExisted(\"/\" + scriptJobName + \"/sharding\"));\n        scheduler = (Scheduler) ReflectionTestUtils.getField(JobRegistry.getInstance().getJobScheduleController(scriptJobName), \"scheduler\");\n        assertTrue(scheduler.isStarted());\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/JobSpringNamespaceWithoutListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/withoutListener.xml\")\nclass JobSpringNamespaceWithoutListenerTest extends AbstractJobSpringIntegrateTest {\n    \n    JobSpringNamespaceWithoutListenerTest() {\n        super(\"simpleElasticJob_namespace\", \"dataflowElasticJob_namespace\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/OneOffJobSpringNamespaceWithEventTraceRdbTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/oneOffWithEventTraceRdb.xml\")\nclass OneOffJobSpringNamespaceWithEventTraceRdbTest extends AbstractOneOffJobSpringIntegrateTest {\n    \n    OneOffJobSpringNamespaceWithEventTraceRdbTest() {\n        super(\"oneOffSimpleElasticJob_namespace_event_trace_rdb\", \"oneOffDataflowElasticJob_namespace_event_trace_rdb\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/OneOffJobSpringNamespaceWithJobHandlerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/oneOffWithJobHandler.xml\")\nclass OneOffJobSpringNamespaceWithJobHandlerTest extends AbstractOneOffJobSpringIntegrateTest {\n    \n    OneOffJobSpringNamespaceWithJobHandlerTest() {\n        super(\"oneOffSimpleElasticJob_namespace_job_handler\", \"oneOffDataflowElasticJob_namespace_job_handler\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/OneOffJobSpringNamespaceWithListenerAndCglibTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/oneOffWithListenerAndCglib.xml\")\nclass OneOffJobSpringNamespaceWithListenerAndCglibTest extends AbstractOneOffJobSpringIntegrateTest {\n    \n    OneOffJobSpringNamespaceWithListenerAndCglibTest() {\n        super(\"simpleElasticJob_namespace_listener_cglib\", \"dataflowElasticJob_namespace_listener_cglib\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/OneOffJobSpringNamespaceWithListenerAndJdkDynamicProxyTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/oneOffWithListenerAndJdkDynamicProxy.xml\")\nclass OneOffJobSpringNamespaceWithListenerAndJdkDynamicProxyTest extends AbstractOneOffJobSpringIntegrateTest {\n    \n    OneOffJobSpringNamespaceWithListenerAndJdkDynamicProxyTest() {\n        super(\"simpleElasticJob_namespace_listener_jdk_proxy\", \"dataflowElasticJob_namespace_listener_jdk_proxy\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/OneOffJobSpringNamespaceWithListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/oneOffWithListener.xml\")\nclass OneOffJobSpringNamespaceWithListenerTest extends AbstractOneOffJobSpringIntegrateTest {\n    \n    OneOffJobSpringNamespaceWithListenerTest() {\n        super(\"simpleElasticJob_namespace_listener\", \"dataflowElasticJob_namespace_listener\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/OneOffJobSpringNamespaceWithRefTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.ref.RefFooSimpleElasticJob;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.awaitility.Awaitility;\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.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(locations = \"classpath:META-INF/job/oneOffWithJobRef.xml\")\nclass OneOffJobSpringNamespaceWithRefTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer(3181);\n    \n    private final String oneOffSimpleJobName = \"oneOffSimpleElasticJobRef\";\n    \n    @Autowired\n    private ApplicationContext applicationContext;\n    \n    @Autowired\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @BeforeEach\n    @AfterEach\n    void reset() {\n        RefFooSimpleElasticJob.reset();\n    }\n    \n    @AfterEach\n    void tearDown() {\n        JobRegistry.getInstance().shutdown(oneOffSimpleJobName);\n    }\n    \n    @Test\n    void assertSpringJobBean() {\n        OneOffJobBootstrap bootstrap = applicationContext.getBean(oneOffSimpleJobName, OneOffJobBootstrap.class);\n        bootstrap.execute();\n        assertOneOffSimpleElasticJobBean();\n    }\n    \n    private void assertOneOffSimpleElasticJobBean() {\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> assertThat(RefFooSimpleElasticJob.isCompleted(), is(true)));\n        assertTrue(RefFooSimpleElasticJob.isCompleted());\n        assertTrue(regCenter.isExisted(\"/\" + oneOffSimpleJobName + \"/sharding\"));\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/OneOffJobSpringNamespaceWithTypeTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n/**\n * todo There is no `echo` program on Windows 11 cmd. Waiting for a fix.\n */\n@EnabledOnOs(OS.LINUX)\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(locations = \"classpath:META-INF/job/oneOffWithJobType.xml\")\nclass OneOffJobSpringNamespaceWithTypeTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer(3181);\n    \n    private final String scriptJobName = \"oneOffScriptElasticJob_job_type\";\n    \n    @Autowired\n    private ApplicationContext applicationContext;\n    \n    @Autowired\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @AfterEach\n    void tearDown() {\n        JobRegistry.getInstance().shutdown(scriptJobName);\n    }\n    \n    @Test\n    void jobScriptWithJobTypeTest() {\n        OneOffJobBootstrap bootstrap = applicationContext.getBean(scriptJobName, OneOffJobBootstrap.class);\n        bootstrap.execute();\n        Awaitility.await().atLeast(1L, TimeUnit.MILLISECONDS).atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> assertTrue(regCenter.isExisted(\"/\" + scriptJobName + \"/sharding\")));\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/job/OneOffJobSpringNamespaceWithoutListenerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.job;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/job/oneOffWithoutListener.xml\")\nclass OneOffJobSpringNamespaceWithoutListenerTest extends AbstractOneOffJobSpringIntegrateTest {\n    \n    OneOffJobSpringNamespaceWithoutListenerTest() {\n        super(\"oneOffSimpleElasticJob\", \"oneOffDataflowElasticJob\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/scanner/AbstractJobSpringIntegrateTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.scanner;\n\nimport lombok.RequiredArgsConstructor;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.annotation.AnnotationSimpleJob;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.awaitility.Awaitility;\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.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\n@ExtendWith(SpringExtension.class)\n@RequiredArgsConstructor\npublic abstract class AbstractJobSpringIntegrateTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer(3181);\n    \n    private final String simpleJobName;\n    \n    @Autowired\n    private CoordinatorRegistryCenter regCenter;\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @BeforeEach\n    @AfterEach\n    void reset() {\n        AnnotationSimpleJob.reset();\n    }\n    \n    @AfterEach\n    void tearDown() {\n        JobRegistry.getInstance().shutdown(simpleJobName);\n    }\n    \n    @Test\n    void assertSpringJobBean() {\n        assertSimpleElasticJobBean();\n    }\n    \n    private void assertSimpleElasticJobBean() {\n        Awaitility.await().atMost(10L, TimeUnit.SECONDS).untilAsserted(() -> assertThat(AnnotationSimpleJob.isCompleted(), is(true)));\n        assertTrue(AnnotationSimpleJob.isCompleted());\n        assertTrue(regCenter.isExisted(\"/\" + simpleJobName + \"/sharding\"));\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/scanner/JobScannerTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.scanner;\n\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(locations = \"classpath:META-INF/scanner/jobScannerContext.xml\")\npublic final class JobScannerTest extends AbstractJobSpringIntegrateTest {\n    \n    public JobScannerTest() {\n        super(\"simpleJob\");\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/snapshot/SnapshotSpringNamespaceDisableTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.snapshot;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport java.io.IOException;\n\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(locations = \"classpath:META-INF/snapshot/snapshotDisabled.xml\")\nclass SnapshotSpringNamespaceDisableTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer(3181);\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @Test\n    void assertSnapshotDisable() {\n        assertThrows(IOException.class, () -> SocketUtils.sendCommand(SnapshotService.DUMP_COMMAND, 9998));\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/snapshot/SnapshotSpringNamespaceEnableTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.snapshot;\n\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport java.io.IOException;\n\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(locations = \"classpath:META-INF/snapshot/snapshotEnabled.xml\")\nclass SnapshotSpringNamespaceEnableTest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer(3181);\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n    }\n    \n    @Test\n    void assertSnapshotEnable() throws IOException {\n        assertNull(SocketUtils.sendCommand(\"unknown_command\", 9988));\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/java/org/apache/shardingsphere/elasticjob/spring/namespace/snapshot/SocketUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.spring.namespace.snapshot;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.net.Socket;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class SocketUtils {\n    \n    /**\n     * Send command.\n     *\n     * @param command  command\n     * @param dumpPort the port for dumping data\n     * @return result of command\n     * @throws IOException io exception\n     */\n    public static String sendCommand(final String command, final int dumpPort) throws IOException {\n        try (\n                Socket socket = new Socket(\"127.0.0.1\", dumpPort);\n                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {\n            writer.write(command);\n            writer.newLine();\n            writer.flush();\n            return reader.readLine();\n        }\n    }\n}\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/base.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://www.springframework.org/schema/context\n                           http://www.springframework.org/schema/context/spring-context.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <context:property-placeholder location=\"classpath:conf/job/conf.properties\" />\n    \n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"${regCenter.serverLists}\" namespace=\"${regCenter.namespace}\" base-sleep-time-milliseconds=\"${regCenter.baseSleepTimeMilliseconds}\" \n                   max-sleep-time-milliseconds=\"${regCenter.maxSleepTimeMilliseconds}\" max-retries=\"${regCenter.maxRetries}\" />\n    \n    <bean id=\"elasticJobTracingDataSource\" class=\"com.zaxxer.hikari.HikariDataSource\" destroy-method=\"close\">\n        <property name=\"driverClassName\" value=\"org.h2.Driver\" />\n        <property name=\"jdbcUrl\" value=\"jdbc:h2:mem:job_event_storage\" />\n        <property name=\"username\" value=\"sa\" />\n        <property name=\"password\" value=\"\" />\n    </bean>\n    <elasticjob:rdb-tracing id=\"elasticJobTrace\" data-source-ref=\"elasticJobTracingDataSource\" />\n    \n    <bean id=\"foo\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.service.FooServiceImpl\" />\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/oneOffWithEventTraceRdb.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <import resource=\"base.xml\" />\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"oneOffSimpleElasticJob_namespace_event_trace_rdb\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\"\n             sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\" job-executor-service-handler-type=\"SINGLE_THREAD\"\n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" />\n    \n    <elasticjob:job id=\"oneOffDataflowElasticJob_namespace_event_trace_rdb\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\"\n             sharding-total-count=\"3\" sharding-item-parameters=\"0=A,1=B,2=C\" job-error-handler-type=\"THROW\" description=\"中文描述\" overwrite=\"true\" />\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/oneOffWithJobHandler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <import resource=\"base.xml\"/>\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"oneOffSimpleElasticJob_namespace_job_handler\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\"\n             sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\" job-executor-service-handler-type=\"SINGLE_THREAD\"\n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" />\n    \n    <elasticjob:job id=\"oneOffDataflowElasticJob_namespace_job_handler\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\"\n             sharding-total-count=\"3\" sharding-item-parameters=\"0=A,1=B,2=C\" job-error-handler-type=\"THROW\" description=\"中文描述\"\n             overwrite=\"true\" />\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/oneOffWithJobRef.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <import resource=\"base.xml\"/>\n    \n    <bean id=\"refSimpleJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.ref.RefFooSimpleElasticJob\">\n        <property name=\"fooService\" ref=\"foo\" />\n    </bean>\n    <bean id=\"refDataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.ref.RefFooDataflowElasticJob\">\n        <property name=\"fooService\" ref=\"foo\" />\n    </bean>\n    \n    <elasticjob:job id=\"oneOffSimpleElasticJobRef\" job-ref=\"refSimpleJob\" registry-center-ref=\"regCenter\"\n             sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\"\n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" job-executor-service-handler-type=\"SINGLE_THREAD\" />\n    \n    <elasticjob:job id=\"oneOffDataflowElasticJob_job_ref\" job-ref=\"refDataflowJob\" registry-center-ref=\"regCenter\"\n             sharding-total-count=\"${dataflowJob.shardingTotalCount}\" sharding-item-parameters=\"${dataflowJob.shardingItemParameters}\"\n             overwrite=\"${dataflowJob.overwrite}\">\n        <props>\n            <prop key=\"streaming.process\">${dataflowJob.streamingProcess}</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/oneOffWithJobType.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <import resource=\"base.xml\"/>\n    \n    <elasticjob:job id=\"oneOffScriptElasticJob_job_type\" job-type=\"SCRIPT\" registry-center-ref=\"regCenter\"\n             sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\"\n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" job-executor-service-handler-type=\"SINGLE_THREAD\" >\n            <props>\n                <prop key=\"script.command.line\">${script.scriptCommandLine}</prop>\n            </props>\n    </elasticjob:job>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/oneOffWithListener.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <import resource=\"base.xml\"/>\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"simpleElasticJob_namespace_listener\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\"\n             sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\"\n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" job-listener-types=\"simpleListener,simpleOnceListener\">\n    </elasticjob:job>\n    \n    <elasticjob:job id=\"dataflowElasticJob_namespace_listener\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\"\n             sharding-total-count=\"3\" sharding-item-parameters=\"0=A,1=B,2=C\" description=\"中文描述\"\n             overwrite=\"true\" />\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/oneOffWithListenerAndCglib.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:aop=\"http://www.springframework.org/schema/aop\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                           http://www.springframework.org/schema/beans/spring-beans.xsd \n                           http://www.springframework.org/schema/context \n                           http://www.springframework.org/schema/context/spring-context.xsd\n                           http://www.springframework.org/schema/aop \n                           http://www.springframework.org/schema/aop/spring-aop.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <context:component-scan base-package=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.aspect,org.apache.shardingsphere.elasticjob.spring.namespace.fixture.service\" />\n    <aop:aspectj-autoproxy proxy-target-class=\"true\" />\n    \n    <import resource=\"base.xml\"/>\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"simpleElasticJob_namespace_listener_cglib\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\" \n             sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\"\n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" job-listener-types=\"simpleCglibListener\">\n    </elasticjob:job>\n    <elasticjob:job id=\"dataflowElasticJob_namespace_listener_cglib\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\" \n             sharding-total-count=\"3\" sharding-item-parameters=\"0=A,1=B,2=C\" description=\"中文描述\"\n             overwrite=\"true\">\n        <props>\n            <prop key=\"streaming.process\">true</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/oneOffWithListenerAndJdkDynamicProxy.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:aop=\"http://www.springframework.org/schema/aop\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://www.springframework.org/schema/context\n                           http://www.springframework.org/schema/context/spring-context.xsd\n                           http://www.springframework.org/schema/aop\n                           http://www.springframework.org/schema/aop/spring-aop.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <context:component-scan base-package=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.aspect,org.apache.shardingsphere.elasticjob.spring.namespace.fixture.service\" />\n    <aop:aspectj-autoproxy />\n    \n    <import resource=\"base.xml\" />\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"simpleElasticJob_namespace_listener_jdk_proxy\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\" \n             sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\"\n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" job-listener-types=\"simpleJdkDynamicProxyListener\">\n    </elasticjob:job>\n    <elasticjob:job id=\"dataflowElasticJob_namespace_listener_jdk_proxy\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\" \n             sharding-total-count=\"3\" sharding-item-parameters=\"0=A,1=B,2=C\" description=\"中文描述\"\n             overwrite=\"true\">\n        <props>\n            <prop key=\"streaming.process\">true</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/oneOffWithoutListener.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <import resource=\"base.xml\" />\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"oneOffSimpleElasticJob\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\"\n             sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\"\n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" />\n    <elasticjob:job id=\"oneOffDataflowElasticJob\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\"\n             sharding-total-count=\"${dataflowJob.shardingTotalCount}\" sharding-item-parameters=\"${dataflowJob.shardingItemParameters}\"\n             monitor-execution=\"${dataflowJob.monitorExecution}\" failover=\"${dataflowJob.failover}\" description=\"${dataflowJob.description}\" \n             disabled=\"${dataflowJob.disabled}\" overwrite=\"${dataflowJob.overwrite}\">\n        <props>\n            <prop key=\"streaming.process\">${dataflowJob.streamingProcess}</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/withEventTraceRdb.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <import resource=\"base.xml\"/>\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"simpleElasticJob_namespace_event_trace_rdb\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\" \n             cron=\"${simpleJob.cron}\" sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\" job-executor-service-handler-type=\"SINGLE_THREAD\" \n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\">\n    </elasticjob:job>\n    \n    <elasticjob:job id=\"dataflowElasticJob_namespace_event_trace_rdb\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\" \n             cron=\"0/1 * * * * ?\" sharding-total-count=\"3\" sharding-item-parameters=\"0=A,1=B,2=C\" job-error-handler-type=\"THROW\" description=\"中文描述\" overwrite=\"true\" />\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/withJobHandler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <import resource=\"base.xml\"/>\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"simpleElasticJob_namespace_job_handler\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\" \n             cron=\"${simpleJob.cron}\" sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\" job-executor-service-handler-type=\"SINGLE_THREAD\" \n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" />\n    \n    <elasticjob:job id=\"dataflowElasticJob_namespace_job_handler\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\" \n             cron=\"0/1 * * * * ?\" sharding-total-count=\"3\" sharding-item-parameters=\"0=A,1=B,2=C\" job-error-handler-type=\"THROW\" description=\"中文描述\" \n             overwrite=\"true\" />\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/withJobRef.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <import resource=\"base.xml\"/>\n    \n    <bean id=\"refSimpleJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.ref.RefFooSimpleElasticJob\">\n        <property name=\"fooService\" ref=\"foo\" />\n    </bean>\n    <bean id=\"refDataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.ref.RefFooDataflowElasticJob\">\n        <property name=\"fooService\" ref=\"foo\" />\n    </bean>\n    \n    <elasticjob:job id=\"simpleElasticJob_job_ref\" job-ref=\"refSimpleJob\" registry-center-ref=\"regCenter\" \n             cron=\"${simpleJob.cron}\" sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\"\n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" job-executor-service-handler-type=\"SINGLE_THREAD\" />\n    \n    <elasticjob:job id=\"dataflowElasticJob_job_ref\" job-ref=\"refDataflowJob\" registry-center-ref=\"regCenter\" \n             cron=\"${dataflowJob.cron}\" sharding-total-count=\"${dataflowJob.shardingTotalCount}\" sharding-item-parameters=\"${dataflowJob.shardingItemParameters}\" \n             overwrite=\"${dataflowJob.overwrite}\">\n        <props>\n            <prop key=\"streaming.process\">${dataflowJob.streamingProcess}</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/withJobType.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <import resource=\"base.xml\"/>\n    \n    <elasticjob:job id=\"scriptElasticJob_job_type\" job-type=\"SCRIPT\" registry-center-ref=\"regCenter\"\n             cron=\"${simpleJob.cron}\" sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\"\n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" job-executor-service-handler-type=\"SINGLE_THREAD\" >\n            <props>\n                <prop key=\"script.command.line\">${script.scriptCommandLine}</prop>\n            </props>\n    </elasticjob:job>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/withListener.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <import resource=\"base.xml\"/>\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"${simpleJob.id}\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\" \n             cron=\"${simpleJob.cron}\" sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\" \n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" job-listener-types=\"simpleListener,simpleOnceListener\">\n    </elasticjob:job>\n    \n    <elasticjob:job id=\"dataflowElasticJob_namespace_listener\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\" \n             cron=\"0/1 * * * * ?\" sharding-total-count=\"3\" sharding-item-parameters=\"0=A,1=B,2=C\" description=\"中文描述\" \n             overwrite=\"true\" />\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/withListenerAndCglib.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:aop=\"http://www.springframework.org/schema/aop\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                           http://www.springframework.org/schema/beans/spring-beans.xsd \n                           http://www.springframework.org/schema/context \n                           http://www.springframework.org/schema/context/spring-context.xsd\n                           http://www.springframework.org/schema/aop \n                           http://www.springframework.org/schema/aop/spring-aop.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <context:component-scan base-package=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.aspect,org.apache.shardingsphere.elasticjob.spring.namespace.fixture.service\" />\n    <aop:aspectj-autoproxy proxy-target-class=\"true\" />\n    \n    <import resource=\"base.xml\"/>\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"simpleElasticJob_namespace_listener_cglib\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\" \n             cron=\"${simpleJob.cron}\" sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\" \n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" job-listener-types=\"simpleCglibListener\">\n    </elasticjob:job>\n    <elasticjob:job id=\"dataflowElasticJob_namespace_listener_cglib\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\" \n             cron=\"0/1 * * * * ?\" sharding-total-count=\"3\" sharding-item-parameters=\"0=A,1=B,2=C\" description=\"中文描述\" \n             overwrite=\"true\">\n        <props>\n            <prop key=\"streaming.process\">true</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/withListenerAndJdkDynamicProxy.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:aop=\"http://www.springframework.org/schema/aop\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://www.springframework.org/schema/context\n                           http://www.springframework.org/schema/context/spring-context.xsd\n                           http://www.springframework.org/schema/aop\n                           http://www.springframework.org/schema/aop/spring-aop.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                           \">\n    <context:component-scan base-package=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.aspect,org.apache.shardingsphere.elasticjob.spring.namespace.fixture.service\" />\n    <aop:aspectj-autoproxy />\n    \n    <import resource=\"base.xml\" />\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"simpleElasticJob_namespace_listener_jdk_proxy\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\" tracing-ref=\"elasticJobTrace\" \n             cron=\"${simpleJob.cron}\" sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\" \n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" job-listener-types=\"simpleJdkDynamicProxyListener\">\n    </elasticjob:job>\n    <elasticjob:job id=\"dataflowElasticJob_namespace_listener_jdk_proxy\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\" \n             cron=\"0/1 * * * * ?\" sharding-total-count=\"3\" sharding-item-parameters=\"0=A,1=B,2=C\" description=\"中文描述\" \n             overwrite=\"true\">\n        <props>\n            <prop key=\"streaming.process\">true</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/job/withoutListener.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <import resource=\"base.xml\" />\n    \n    <bean id=\"fooJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.FooSimpleElasticJob\" />\n    <bean id=\"dataflowJob\" class=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.DataflowElasticJob\" />\n    \n    <elasticjob:job id=\"simpleElasticJob_namespace\" job-ref=\"fooJob\" registry-center-ref=\"regCenter\" \n             cron=\"${simpleJob.cron}\" sharding-total-count=\"${simpleJob.shardingTotalCount}\" sharding-item-parameters=\"${simpleJob.shardingItemParameters}\" \n             disabled=\"${simpleJob.disabled}\" overwrite=\"${simpleJob.overwrite}\" />\n    <elasticjob:job id=\"dataflowElasticJob_namespace\" job-ref=\"dataflowJob\" registry-center-ref=\"regCenter\" \n             sharding-total-count=\"${dataflowJob.shardingTotalCount}\" cron=\"${dataflowJob.cron}\" sharding-item-parameters=\"${dataflowJob.shardingItemParameters}\" \n             monitor-execution=\"${dataflowJob.monitorExecution}\" failover=\"${dataflowJob.failover}\" description=\"${dataflowJob.description}\" \n             disabled=\"${dataflowJob.disabled}\" overwrite=\"${dataflowJob.overwrite}\">\n        <props>\n            <prop key=\"streaming.process\">${dataflowJob.streamingProcess}</prop>\n        </props>\n    </elasticjob:job>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/reg/regContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://www.springframework.org/schema/context \n                        http://www.springframework.org/schema/context/spring-context.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <context:property-placeholder location=\"classpath:conf/reg/conf.properties\" ignore-unresolvable=\"true\" />\n    <elasticjob:zookeeper id=\"regCenter1\" server-lists=\"${regCenter1.serverLists}\" namespace=\"${regCenter1.namespace}\" base-sleep-time-milliseconds=\"${regCenter1.baseSleepTimeMilliseconds}\" max-sleep-time-milliseconds=\"${regCenter1.maxSleepTimeMilliseconds}\" max-retries=\"${regCenter1.maxRetries}\" />\n    <elasticjob:zookeeper id=\"regCenter2\" server-lists=\"${regCenter2.serverLists}\" namespace=\"${regCenter2.namespace}\" base-sleep-time-milliseconds=\"${regCenter2.baseSleepTimeMilliseconds}\" max-sleep-time-milliseconds=\"${regCenter2.maxSleepTimeMilliseconds}\" max-retries=\"${regCenter2.maxRetries}\" session-timeout-milliseconds=\"${regCenter2.sessionTimeoutMilliseconds}\" connection-timeout-milliseconds=\"${regCenter2.connectionTimeoutMilliseconds}\" digest=\"${regCenter2.digest}\" />\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/scanner/jobScannerContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n    xsi:schemaLocation=\"http://www.springframework.org/schema/beans \n                        http://www.springframework.org/schema/beans/spring-beans.xsd \n                        http://www.springframework.org/schema/context \n                        http://www.springframework.org/schema/context/spring-context.xsd \n                        http://shardingsphere.apache.org/schema/elasticjob\n                        http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <context:property-placeholder location=\"classpath:conf/job/conf.properties\" />\n\n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"${regCenter.serverLists}\" namespace=\"${regCenter.namespace}\" base-sleep-time-milliseconds=\"${regCenter.baseSleepTimeMilliseconds}\"\n                          max-sleep-time-milliseconds=\"${regCenter.maxSleepTimeMilliseconds}\" max-retries=\"${regCenter.maxRetries}\" />\n\n    <elasticjob:job-scanner id=\"job-scanner\" base-package=\"org.apache.shardingsphere.elasticjob.spring.namespace.fixture.job.annotation\"/>\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.spring.namespace.fixture.listener.SimpleCglibListener\norg.apache.shardingsphere.elasticjob.spring.namespace.fixture.listener.SimpleJdkDynamicProxyListener\norg.apache.shardingsphere.elasticjob.spring.namespace.fixture.listener.SimpleListener\norg.apache.shardingsphere.elasticjob.spring.namespace.fixture.listener.SimpleOnceListener\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/snapshot/snapshotDisabled.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://www.springframework.org/schema/context\n                           http://www.springframework.org/schema/context/spring-context.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <context:property-placeholder location=\"classpath:conf/reg/conf.properties\" ignore-unresolvable=\"true\" />\n    \n    <elasticjob:zookeeper id=\"regCenter1\" server-lists=\"${regCenter1.serverLists}\" namespace=\"${regCenter1.namespace}\"\n                          base-sleep-time-milliseconds=\"${regCenter1.baseSleepTimeMilliseconds}\"\n                          max-sleep-time-milliseconds=\"${regCenter1.maxSleepTimeMilliseconds}\"\n                          max-retries=\"${regCenter1.maxRetries}\" />\n    \n    <elasticjob:snapshot id=\"jobSnapshotDisabled\" registry-center-ref=\"regCenter1\" dump-port=\"9987\" />\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/META-INF/snapshot/snapshotEnabled.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:context=\"http://www.springframework.org/schema/context\"\n       xmlns:elasticjob=\"http://shardingsphere.apache.org/schema/elasticjob\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n                           http://www.springframework.org/schema/beans/spring-beans.xsd\n                           http://www.springframework.org/schema/context\n                           http://www.springframework.org/schema/context/spring-context.xsd\n                           http://shardingsphere.apache.org/schema/elasticjob\n                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd\n                        \">\n    <context:property-placeholder location=\"classpath:conf/job/conf.properties\" ignore-unresolvable=\"true\" />\n    \n    <elasticjob:zookeeper id=\"regCenter\" server-lists=\"${regCenter.serverLists}\" namespace=\"${regCenter.namespace}\"\n                          base-sleep-time-milliseconds=\"${regCenter.baseSleepTimeMilliseconds}\"\n                          max-sleep-time-milliseconds=\"${regCenter.maxSleepTimeMilliseconds}\"\n                          max-retries=\"${regCenter.maxRetries}\" />\n    \n    <elasticjob:snapshot id=\"jobSnapshotEnabled\" registry-center-ref=\"regCenter\" dump-port=\"9988\" />\n</beans>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/conf/job/conf.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nregCenter.serverLists=127.0.0.1:3181\nregCenter.namespace=elasticjob-spring-test\nregCenter.baseSleepTimeMilliseconds=1000\nregCenter.maxSleepTimeMilliseconds=3000\nregCenter.maxRetries=3\n\nsimpleJob.id=simpleElasticJob_namespace_listener\nsimpleJob.cron=0/1 * * * * ?\nsimpleJob.shardingTotalCount=3\nsimpleJob.shardingItemParameters=0=A,1=B,2=C\nsimpleJob.disabled=false\nsimpleJob.overwrite=true\n\ndataflowJob.cron=0/1 * * * * ?\ndataflowJob.shardingTotalCount=3\ndataflowJob.shardingItemParameters=0=A,1=B,2=C\ndataflowJob.monitorExecution=true\ndataflowJob.failover=true\ndataflowJob.description=Examples of jobs that do not stop running\ndataflowJob.disabled=false\ndataflowJob.overwrite=true\ndataflowJob.streamingProcess=true\n\n# need absolute path\n#script.scriptCommandLine=your_path/elasticjob/elasticjob-spring/src/test/resources/script/demo.sh\nscript.scriptCommandLine=echo test\n"
  },
  {
    "path": "spring/namespace/src/test/resources/conf/reg/conf.properties",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\nregCenter1.serverLists=127.0.0.1:3181\nregCenter1.namespace=regCenter1\nregCenter1.baseSleepTimeMilliseconds=1000\nregCenter1.maxSleepTimeMilliseconds=3000\nregCenter1.maxRetries=3\n\nregCenter2.serverLists=127.0.0.1:3181\nregCenter2.namespace=regCenter2\nregCenter2.baseSleepTimeMilliseconds=1000\nregCenter2.maxSleepTimeMilliseconds=3000\nregCenter2.maxRetries=3\nregCenter2.sessionTimeoutMilliseconds=1000\nregCenter2.connectionTimeoutMilliseconds=1000\nregCenter2.digest=test:digest\n"
  },
  {
    "path": "spring/namespace/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <level value=\"WARN\" />\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.zookeeper\" level=\"ERROR\" />\n    <logger name=\"org.apache.curator\" level=\"ERROR\" />\n    <logger name=\"org.apache.shardingsphere.elasticjob.kernel.internal.executor.error.handler.type.LogJobErrorHandler\" level=\"OFF\" />\n</configuration>\n"
  },
  {
    "path": "spring/namespace/src/test/resources/script/demo.bat",
    "content": "@rem\n@rem Licensed to the Apache Software Foundation (ASF) under one or more\n@rem contributor license agreements.  See the NOTICE file distributed with\n@rem this work for additional information regarding copyright ownership.\n@rem The ASF licenses this file to You under the Apache License, Version 2.0\n@rem (the \"License\"); you may not use this file except in compliance with\n@rem the License.  You may obtain a copy of the License at\n@rem\n@rem     http://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n\n@echo Sharding Context: %*\n"
  },
  {
    "path": "spring/namespace/src/test/resources/script/demo.sh",
    "content": "#!/bin/bash\n#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\necho Sharding Context: $*\n"
  },
  {
    "path": "spring/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-spring</artifactId>\n    <packaging>pom</packaging>\n    <name>${project.artifactId}</name>\n    \n    <modules>\n        <module>core</module>\n        <module>boot-starter</module>\n        <module>namespace</module>\n    </modules>\n    \n    <properties>\n        <aspectj.version>1.9.22.1</aspectj.version>\n    </properties>\n    \n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-bom</artifactId>\n                <version>${netty.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-framework-bom</artifactId>\n                <version>${spring-framework.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring-boot-dependencies.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            \n            <dependency>\n                <groupId>org.aspectj</groupId>\n                <artifactId>aspectjweaver</artifactId>\n                <version>${aspectj.version}</version>\n                <scope>test</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n</project>\n"
  },
  {
    "path": "src/resources/checkstyle.xml",
    "content": "<?xml version=\"1.0\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<!DOCTYPE module PUBLIC \"-//Puppy Crawl//DTD Check Configuration 1.3//EN\" \"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd\">\n<module name=\"Checker\">\n    <property name=\"severity\" value=\"error\" />\n    <property name=\"fileExtensions\" value=\"java, xml, properties\" />\n    \n    <module name=\"SeverityMatchFilter\" />\n    \n    <module name=\"Header\">\n        <property name=\"fileExtensions\" value=\"java\" />\n    </module>\n    <module name=\"FileTabCharacter\">\n        <property name=\"eachLine\" value=\"true\" />\n    </module>\n    <module name=\"FileLength\" />\n    <module name=\"LineLength\">\n        <property name=\"fileExtensions\" value=\"java\" />\n        <property name=\"max\" value=\"200\" />\n    </module>\n    <module name=\"NewlineAtEndOfFile\">\n        <property name=\"lineSeparator\" value=\"lf\" />\n    </module>\n    <module name=\"Translation\" />\n    <module name=\"UniqueProperties\" />\n    \n    <module name=\"TreeWalker\">\n        <module name=\"SuppressionCommentFilter\" />\n        \n        <!-- Annotations -->\n        <module name=\"AnnotationLocation\">\n            <property name=\"id\" value=\"AnnotationLocationMostCases\" />\n            <property name=\"tokens\" value=\"CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF\" />\n        </module>\n        <module name=\"AnnotationLocation\">\n            <property name=\"id\" value=\"AnnotationLocationVariables\" />\n            <property name=\"tokens\" value=\"VARIABLE_DEF\" />\n            <property name=\"allowSamelineMultipleAnnotations\" value=\"true\" />\n        </module>\n        <module name=\"AnnotationUseStyle\" />\n        <module name=\"MissingDeprecated\" />\n        <module name=\"MissingOverride\" />\n        <module name=\"PackageAnnotation\" />\n        <module name=\"SuppressWarnings\" />\n        <module name=\"SuppressWarningsHolder\" />\n        \n        <!-- Block Checks -->\n        <module name=\"AvoidNestedBlocks\" />\n        <module name=\"EmptyBlock\" />\n        <module name=\"EmptyCatchBlock\">\n            <property name=\"exceptionVariableName\" value=\"expected|ignore\" />\n        </module>\n        <module name=\"LeftCurly\" />\n        <module name=\"RightCurly\" />\n        <module name=\"NeedBraces\" />\n        \n        <!-- Class Design -->\n        <module name=\"FinalClass\" />\n        <!-- cannot recognize for lombok @NoArgsConstructor(access = AccessLevel.PRIVATE), just ignore -->\n        <!--<module name=\"HideUtilityClassConstructor\" />-->\n        <module name=\"InnerTypeLast\" />\n        <module name=\"InterfaceIsType\" />\n        <module name=\"MutableException\" />\n        <module name=\"OneTopLevelClass\" />\n        <module name=\"ThrowsCount\">\n            <property name=\"ignorePrivateMethods\" value=\"false\" />\n        </module>\n        <module name=\"VisibilityModifier\" />\n        \n        <!-- Coding -->\n        <module name=\"AvoidDoubleBraceInitialization\" />\n        <module name=\"AvoidNoArgumentSuperConstructorCall\" />\n        <module name=\"CovariantEquals\" />\n        <module name=\"DeclarationOrder\" />\n        <module name=\"DefaultComesLast\" />\n        <module name=\"EmptyStatement\" />\n        <module name=\"EqualsAvoidNull\" />\n        <module name=\"EqualsHashCode\" />\n        <module name=\"ExplicitInitialization\" />\n        <module name=\"FallThrough\" />\n        <module name=\"IllegalCatch\" />\n        <module name=\"IllegalInstantiation\" />\n        <module name=\"IllegalThrows\" />\n        <module name=\"IllegalToken\" />\n        <module name=\"IllegalTokenText\">\n            <property name=\"tokens\" value=\"STRING_LITERAL, CHAR_LITERAL\" />\n            <property name=\"format\" value=\"\\\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\\\(0(10|11|12|14|15|42|47)|134)\" />\n            <property name=\"message\" value=\"Consider using special escape sequence instead of octal value or Unicode escaped value.\" />\n        </module>\n        <module name=\"IllegalType\" />\n        <module name=\"MissingSwitchDefault\" />\n        <module name=\"ModifiedControlVariable\" />\n        <module name=\"MultipleVariableDeclarations\" />\n        <module name=\"NestedForDepth\">\n            <property name=\"severity\" value=\"warning\" />\n        </module>\n        <module name=\"NestedIfDepth\" />\n        <module name=\"NestedTryDepth\" />\n        <module name=\"NoArrayTrailingComma\" />\n        <module name=\"NoClone\" />\n        <module name=\"NoEnumTrailingComma\" />\n        <module name=\"NoFinalizer\" />\n        <module name=\"OneStatementPerLine\" />\n        <module name=\"OverloadMethodsDeclarationOrder\" />\n        <module name=\"PackageDeclaration\" />\n        <module name=\"ParameterAssignment\" />\n        <module name=\"RequireThis\" />\n        <module name=\"SimplifyBooleanExpression\" />\n        <module name=\"SimplifyBooleanReturn\" />\n        <module name=\"StringLiteralEquality\" />\n        <module name=\"SuperClone\" />\n        <module name=\"SuperFinalize\" />\n        <module name=\"UnnecessaryParentheses\" />\n        <module name=\"UnnecessarySemicolonAfterOuterTypeDeclaration\" />\n        <module name=\"UnnecessarySemicolonAfterTypeMemberDeclaration\" />\n        <module name=\"UnnecessarySemicolonInEnumeration\" />\n        <module name=\"UnnecessarySemicolonInTryWithResources\" />\n        <module name=\"UnusedLocalVariable\" />\n        <module name=\"VariableDeclarationUsageDistance\" />\n        \n        <!-- Imports -->\n        <module name=\"AvoidStarImport\" />\n        <module name=\"AvoidStaticImport\">\n            <property name=\"excludes\" value=\"org.junit.jupiter.api.Assertions.*,org.junit.jupiter.api.Assumptions.*,org.hamcrest.Matchers.*,org.hamcrest.CoreMatchers.*,org.hamcrest.MatcherAssert.*,org.mockito.Mockito.*,org.mockito.ArgumentMatchers.*\" />\n        </module>\n        <module name=\"IllegalImport\" />\n        <module name=\"RedundantImport\" />\n        <module name=\"UnusedImports\" />\n        \n        <!-- Javadoc Comments -->\n        <module name=\"AtclauseOrder\">\n            <property name=\"tagOrder\" value=\"@param, @return, @throws, @deprecated\" />\n        </module>\n        <module name=\"InvalidJavadocPosition\" />\n        <module name=\"JavadocBlockTagLocation\" />\n        <module name=\"JavadocContentLocation\" />\n        <module name=\"JavadocMethod\">\n            <property name=\"allowedAnnotations\" value=\"Override, Test, BeforeEach, AfterEach, BeforeAll, AfterAll, ParameterizedTest\" />\n            <property name=\"tokens\" value=\"METHOD_DEF, ANNOTATION_FIELD_DEF\" />\n        </module>\n        <module name=\"JavadocMissingLeadingAsterisk\" />\n        <module name=\"JavadocMissingWhitespaceAfterAsterisk\" />\n        <module name=\"JavadocParagraph\">\n            <property name=\"violateExecutionOnNonTightHtml\" value=\"true\" />\n            <property name=\"allowNewlineParagraph\" value=\"false\" />\n        </module>\n        <module name=\"JavadocStyle\" />\n        <module name=\"JavadocTagContinuationIndentation\">\n            <property name=\"violateExecutionOnNonTightHtml\" value=\"true\" />\n        </module>\n        <module name=\"JavadocType\" />\n        <module name=\"MissingJavadocMethod\">\n            <property name=\"allowMissingPropertyJavadoc\" value=\"true\" />\n            <property name=\"tokens\" value=\"METHOD_DEF\" />\n        </module>\n        <module name=\"MissingJavadocPackage\" />\n        <module name=\"NonEmptyAtclauseDescription\">\n            <property name=\"violateExecutionOnNonTightHtml\" value=\"true\" />\n        </module>\n        <module name=\"SingleLineJavadoc\">\n            <property name=\"violateExecutionOnNonTightHtml\" value=\"true\" />\n            <property name=\"ignoreInlineTags\" value=\"false\" />\n        </module>\n        <module name=\"SummaryJavadoc\">\n            <property name=\"violateExecutionOnNonTightHtml\" value=\"true\" />\n        </module>\n        \n        <!-- Metrics -->\n        <module name=\"BooleanExpressionComplexity\">\n            <property name=\"severity\" value=\"warning\" />\n        </module>\n        <module name=\"ClassDataAbstractionCoupling\">\n            <property name=\"severity\" value=\"warning\" />\n            <property name=\"max\" value=\"10\" />\n        </module>\n        <module name=\"ClassFanOutComplexity\">\n            <property name=\"severity\" value=\"warning\" />\n        </module>\n        <module name=\"CyclomaticComplexity\">\n            <property name=\"severity\" value=\"warning\" />\n        </module>\n        <module name=\"JavaNCSS\">\n            <property name=\"severity\" value=\"warning\" />\n        </module>\n        <module name=\"NPathComplexity\">\n            <property name=\"severity\" value=\"warning\" />\n        </module>\n        \n        <!-- Miscellaneous -->\n        <module name=\"ArrayTypeStyle\" />\n        <module name=\"AvoidEscapedUnicodeCharacters\" />\n        <module name=\"CommentsIndentation\" />\n        <module name=\"DescendantToken\" />\n        <module name=\"FinalParameters\" />\n        <module name=\"Indentation\">\n            <property name=\"arrayInitIndent\" value=\"2\" />\n            <property name=\"lineWrappingIndentation\" value=\"8\" />\n        </module>\n        <module name=\"NoCodeInFile\" />\n        <module name=\"OuterTypeFilename\" />\n        <module name=\"TodoComment\" />\n        <module name=\"TrailingComment\" />\n        <module name=\"UncommentedMain\">\n            <property name=\"excludedClasses\" value=\"\\.Bootstrap\" />\n        </module>\n        <module name=\"UpperEll\" />\n        \n        <!-- Modifiers -->\n        <module name=\"ModifierOrder\" />\n        <module name=\"RedundantModifier\" />\n        \n        <!-- Naming Conventions -->\n        <module name=\"AbbreviationAsWordInName\">\n            <property name=\"allowedAbbreviationLength\" value=\"8\" />\n        </module>\n        <module name=\"CatchParameterName\" />\n        <module name=\"ClassTypeParameterName\" />\n        <module name=\"ConstantName\" />\n        <module name=\"InterfaceTypeParameterName\" />\n        <module name=\"LambdaParameterName\" />\n        <module name=\"LocalFinalVariableName\" />\n        <module name=\"LocalVariableName\" />\n        <module name=\"MemberName\" />\n        <module name=\"MethodName\" />\n        <module name=\"MethodTypeParameterName\" />\n        <module name=\"PackageName\">\n            <property name=\"format\" value=\"^[a-z]+(\\.[a-z][a-z0-9]*)*$\" />\n        </module>\n        <module name=\"ParameterName\" />\n        <module name=\"PatternVariableName\" />\n        <module name=\"RecordComponentName\" />\n        <module name=\"RecordTypeParameterName\" />\n        <module name=\"StaticVariableName\" />\n        <module name=\"TypeName\" />\n        \n        <!-- Size Violations -->\n        <module name=\"AnonInnerLength\" />\n        <module name=\"ExecutableStatementCount\">\n            <property name=\"severity\" value=\"warning\" />\n            <property name=\"max\" value=\"50\" />\n        </module>\n<!--        <module name=\"LambdaBodyLength\" />-->\n        <module name=\"MethodCount\">\n            <property name=\"severity\" value=\"warning\" />\n        </module>\n        <module name=\"MethodLength\" />\n        <module name=\"OuterTypeNumber\" />\n        <module name=\"RecordComponentNumber\" />\n        \n        <!-- Whitespace -->\n        <module name=\"EmptyForInitializerPad\" />\n        <module name=\"EmptyForIteratorPad\" />\n        <module name=\"EmptyLineSeparator\">\n            <property name=\"allowMultipleEmptyLines\" value=\"false\" />\n            <property name=\"allowMultipleEmptyLinesInsideClassMembers\" value=\"false\" />\n        </module>\n        <module name=\"GenericWhitespace\" />\n        <module name=\"MethodParamPad\" />\n        <module name=\"NoLineWrap\" />\n        <module name=\"NoWhitespaceAfter\" />\n        <module name=\"NoWhitespaceBefore\" />\n        <module name=\"NoWhitespaceBeforeCaseDefaultColon\" />\n        <module name=\"OperatorWrap\" />\n        <module name=\"ParenPad\" />\n        <module name=\"SeparatorWrap\">\n            <property name=\"id\" value=\"SeparatorWrapDot\" />\n            <property name=\"tokens\" value=\"DOT\" />\n            <property name=\"option\" value=\"nl\" />\n        </module>\n        <module name=\"SeparatorWrap\">\n            <property name=\"id\" value=\"SeparatorWrapComma\" />\n            <property name=\"tokens\" value=\"COMMA\" />\n            <property name=\"option\" value=\"EOL\" />\n        </module>\n        <module name=\"SeparatorWrap\">\n            <property name=\"id\" value=\"SeparatorWrapEllipsis\" />\n            <property name=\"tokens\" value=\"ELLIPSIS\" />\n            <property name=\"option\" value=\"EOL\" />\n        </module>\n        <module name=\"SeparatorWrap\">\n            <property name=\"id\" value=\"SeparatorWrapArrayDeclarator\" />\n            <property name=\"tokens\" value=\"ARRAY_DECLARATOR\" />\n            <property name=\"option\" value=\"EOL\" />\n        </module>\n        <module name=\"SeparatorWrap\">\n            <property name=\"id\" value=\"SeparatorWrapMethodRef\" />\n            <property name=\"tokens\" value=\"METHOD_REF\" />\n            <property name=\"option\" value=\"nl\" />\n        </module>\n        <module name=\"SingleSpaceSeparator\">\n            <property name=\"validateComments\" value=\"true\" />\n        </module>\n        <module name=\"TypecastParenPad\" />\n        <module name=\"WhitespaceAfter\" />\n        <module name=\"WhitespaceAround\" />\n    </module>\n</module>\n"
  },
  {
    "path": "src/resources/spotless/copyright.txt",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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"
  },
  {
    "path": "src/resources/spotless/java.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<profiles version=\"13\">\n    <profile kind=\"CodeFormatterProfile\" name=\"'ShardingSphere Apache Current'\" version=\"13\">\n        <setting id=\"org.eclipse.jdt.core.compiler.source\" value=\"1.8\" />\n        <setting id=\"org.eclipse.jdt.core.compiler.compliance\" value=\"1.8\" />\n        <setting id=\"org.eclipse.jdt.core.compiler.codegen.targetPlatform\" value=\"1.8\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_empty_lines\" value=\"true\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.tabulation.size\" value=\"4\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.lineSplit\" value=\"200\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.line_length\" value=\"200\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.tabulation.char\" value=\"space\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.indentation.size\" value=\"1\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration\" value=\"1\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_javadoc_comments\" value=\"false\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.join_wrapped_lines\" value=\"false\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional\" value=\"insert\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default\" value=\"do not insert\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_enum_constants\" value=\"16\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement\" value=\"do not insert\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case\" value=\"do not insert\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_conditional_expression\" value=\"80\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_assignment\" value=\"16\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_package\" value=\"1\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer\" value=\"2\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_resources_in_try\" value=\"160\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration\" value=\"10\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration\" value=\"106\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration\" value=\"106\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration\" value=\"106\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call.count_dependent\" value=\"16|5|80\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation\" value=\"16\" />\n    </profile>\n</profiles>\n"
  },
  {
    "path": "test/e2e/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-test</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-test-e2e</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <properties>\n        <maven.deploy.skip>true</maven.deploy.skip>\n    </properties>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-bootstrap</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-test-util</artifactId>\n            <version>${project.parent.version}</version>\n        </dependency>\n        \n        <dependency>\n            <groupId>org.awaitility</groupId>\n            <artifactId>awaitility</artifactId>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/annotation/BaseAnnotationE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.annotation;\n\nimport lombok.AccessLevel;\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.JobBootstrap;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.annotation.JobAnnotationBuilder;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\n\n@Getter(AccessLevel.PROTECTED)\npublic abstract class BaseAnnotationE2ETest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static ZookeeperConfiguration zookeeperConfig;\n    \n    @Getter(AccessLevel.PROTECTED)\n    private static CoordinatorRegistryCenter registryCenter;\n    \n    private final ElasticJob elasticJob;\n    \n    private final JobConfiguration jobConfiguration;\n    \n    private final JobBootstrap jobBootstrap;\n    \n    private final LeaderService leaderService;\n    \n    private final String jobName;\n    \n    protected BaseAnnotationE2ETest(final TestType type, final ElasticJob elasticJob) {\n        this.elasticJob = elasticJob;\n        jobConfiguration = JobAnnotationBuilder.generateJobConfiguration(elasticJob.getClass());\n        jobName = jobConfiguration.getJobName();\n        jobBootstrap = createJobBootstrap(type, elasticJob);\n        leaderService = new LeaderService(registryCenter, jobName);\n    }\n    \n    private JobBootstrap createJobBootstrap(final TestType type, final ElasticJob elasticJob) {\n        switch (type) {\n            case SCHEDULE:\n                return new ScheduleJobBootstrap(registryCenter, elasticJob);\n            case ONE_OFF:\n                return new OneOffJobBootstrap(registryCenter, elasticJob);\n            default:\n                throw new RuntimeException(String.format(\"Cannot support `%s`\", type));\n        }\n    }\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n        zookeeperConfig = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), \"zkRegTestCenter\");\n        registryCenter = new ZookeeperRegistryCenter(zookeeperConfig);\n        zookeeperConfig.setConnectionTimeoutMilliseconds(30000);\n        registryCenter.init();\n    }\n    \n    @BeforeEach\n    void setUp() {\n        if (jobBootstrap instanceof ScheduleJobBootstrap) {\n            ((ScheduleJobBootstrap) jobBootstrap).schedule();\n        } else {\n            ((OneOffJobBootstrap) jobBootstrap).execute();\n        }\n    }\n    \n    @AfterEach\n    void tearDown() {\n        jobBootstrap.shutdown();\n        ReflectionUtils.setFieldValue(JobRegistry.getInstance(), \"instance\", null);\n    }\n    \n    public enum TestType {\n        \n        SCHEDULE, ONE_OFF\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/annotation/OneOffEnabledJobE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.annotation;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.env.IpUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerStatus;\nimport org.apache.shardingsphere.elasticjob.test.e2e.annotation.fixture.AnnotationUnShardingJob;\nimport org.awaitility.Awaitility;\nimport org.hamcrest.MatcherAssert;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass OneOffEnabledJobE2ETest extends BaseAnnotationE2ETest {\n    \n    OneOffEnabledJobE2ETest() {\n        super(TestType.ONE_OFF, new AnnotationUnShardingJob());\n    }\n    \n    @BeforeEach\n    void assertEnabledRegCenterInfo() {\n        assertThat(JobRegistry.getInstance().getCurrentShardingTotalCount(getJobName()), is(1));\n        assertThat(JobRegistry.getInstance().getJobInstance(getJobName()).getServerIp(), is(IpUtils.getIp()));\n        JobConfiguration jobConfig = YamlEngine.unmarshal(getRegistryCenter().get(\"/\" + getJobName() + \"/config\"), JobConfigurationPOJO.class).toJobConfiguration();\n        assertThat(jobConfig.getShardingTotalCount(), is(1));\n        assertNull(jobConfig.getCron());\n        assertThat(getRegistryCenter().get(\"/\" + getJobName() + \"/servers/\" + JobRegistry.getInstance().getJobInstance(getJobName()).getServerIp()), is(ServerStatus.ENABLED.name()));\n        assertThat(getRegistryCenter().get(\"/\" + getJobName() + \"/leader/election/instance\"), is(JobRegistry.getInstance().getJobInstance(getJobName()).getJobInstanceId()));\n        assertTrue(getRegistryCenter().isExisted(\"/\" + getJobName() + \"/instances/\" + JobRegistry.getInstance().getJobInstance(getJobName()).getJobInstanceId()));\n        getRegistryCenter().remove(\"/\" + getJobName() + \"/leader/election\");\n        assertTrue(getLeaderService().isLeaderUntilBlock());\n    }\n    \n    @Test\n    void assertJobInit() {\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> MatcherAssert.assertThat(((AnnotationUnShardingJob) getElasticJob()).isCompleted(), is(true)));\n        assertTrue(getRegistryCenter().isExisted(\"/\" + getJobName() + \"/sharding\"));\n    }\n    \n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/annotation/ScheduleEnabledJobE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.annotation;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.env.IpUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerStatus;\nimport org.apache.shardingsphere.elasticjob.test.e2e.annotation.fixture.AnnotationSimpleJob;\nimport org.awaitility.Awaitility;\nimport org.hamcrest.MatcherAssert;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ScheduleEnabledJobE2ETest extends BaseAnnotationE2ETest {\n    \n    ScheduleEnabledJobE2ETest() {\n        super(TestType.SCHEDULE, new AnnotationSimpleJob());\n    }\n    \n    @BeforeEach\n    void assertEnabledRegCenterInfo() {\n        assertThat(JobRegistry.getInstance().getCurrentShardingTotalCount(getJobName()), is(3));\n        assertThat(JobRegistry.getInstance().getJobInstance(getJobName()).getServerIp(), is(IpUtils.getIp()));\n        JobConfiguration jobConfig = YamlEngine.unmarshal(getRegistryCenter().get(\"/\" + getJobName() + \"/config\"), JobConfigurationPOJO.class).toJobConfiguration();\n        assertThat(jobConfig.getShardingTotalCount(), is(3));\n        assertThat(jobConfig.getCron(), is(\"*/10 * * * * ?\"));\n        assertNull(jobConfig.getTimeZone());\n        assertThat(jobConfig.getShardingItemParameters(), is(\"0=a,1=b,2=c\"));\n        assertThat(getRegistryCenter().get(\"/\" + getJobName() + \"/servers/\" + JobRegistry.getInstance().getJobInstance(getJobName()).getServerIp()), is(ServerStatus.ENABLED.name()));\n        assertThat(getRegistryCenter().get(\"/\" + getJobName() + \"/leader/election/instance\"), is(JobRegistry.getInstance().getJobInstance(getJobName()).getJobInstanceId()));\n        assertTrue(getRegistryCenter().isExisted(\"/\" + getJobName() + \"/instances/\" + JobRegistry.getInstance().getJobInstance(getJobName()).getJobInstanceId()));\n        getRegistryCenter().remove(\"/\" + getJobName() + \"/leader/election\");\n        assertTrue(getLeaderService().isLeaderUntilBlock());\n    }\n    \n    @Test\n    void assertJobInit() {\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> MatcherAssert.assertThat(((AnnotationSimpleJob) getElasticJob()).isCompleted(), is(true)));\n        assertTrue(getRegistryCenter().isExisted(\"/\" + getJobName() + \"/sharding\"));\n    }\n    \n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/annotation/fixture/AnnotationSimpleJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.annotation.fixture;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobConfiguration;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobProp;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\n@ElasticJobConfiguration(\n        jobName = \"AnnotationSimpleJob\",\n        description = \"desc\",\n        shardingTotalCount = 3,\n        shardingItemParameters = \"0=a,1=b,2=c\",\n        cron = \"*/10 * * * * ?\",\n        props = {\n                @ElasticJobProp(key = \"print.title\", value = \"test title\"),\n                @ElasticJobProp(key = \"print.content\", value = \"test content\")\n        })\n@Getter\npublic class AnnotationSimpleJob implements SimpleJob {\n    \n    private volatile boolean completed;\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        completed = true;\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/annotation/fixture/AnnotationUnShardingJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.annotation.fixture;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.annotation.ElasticJobConfiguration;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\n@ElasticJobConfiguration(jobName = \"AnnotationUnShardingJob\", description = \"desc\", shardingTotalCount = 1)\n@Getter\npublic final class AnnotationUnShardingJob implements SimpleJob {\n    \n    private volatile boolean completed;\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        completed = true;\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/BaseE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw;\n\nimport lombok.AccessLevel;\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.JobBootstrap;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.election.LeaderService;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\n\n@Getter(AccessLevel.PROTECTED)\npublic abstract class BaseE2ETest {\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    private static ZookeeperConfiguration zookeeperConfig;\n    \n    @Getter(AccessLevel.PROTECTED)\n    private static CoordinatorRegistryCenter registryCenter;\n    \n    private final ElasticJob elasticJob;\n    \n    private final JobConfiguration jobConfiguration;\n    \n    private final JobBootstrap jobBootstrap;\n    \n    private final LeaderService leaderService;\n    \n    private final String jobName = System.nanoTime() + \"_test_job\";\n    \n    protected BaseE2ETest(final TestType type, final ElasticJob elasticJob) {\n        this.elasticJob = elasticJob;\n        jobConfiguration = getJobConfiguration(jobName);\n        jobBootstrap = createJobBootstrap(type, elasticJob);\n        leaderService = new LeaderService(registryCenter, jobName);\n    }\n    \n    protected abstract JobConfiguration getJobConfiguration(String jobName);\n    \n    private JobBootstrap createJobBootstrap(final TestType type, final ElasticJob elasticJob) {\n        switch (type) {\n            case SCHEDULE:\n                return new ScheduleJobBootstrap(registryCenter, elasticJob, jobConfiguration);\n            case ONE_OFF:\n                return new OneOffJobBootstrap(registryCenter, elasticJob, jobConfiguration);\n            default:\n                throw new RuntimeException(String.format(\"Cannot support `%s`\", type));\n        }\n    }\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n        zookeeperConfig = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), \"zkRegTestCenter\");\n        registryCenter = new ZookeeperRegistryCenter(zookeeperConfig);\n        zookeeperConfig.setConnectionTimeoutMilliseconds(30000);\n        registryCenter.init();\n    }\n    \n    @BeforeEach\n    void setUp() {\n        if (jobBootstrap instanceof ScheduleJobBootstrap) {\n            ((ScheduleJobBootstrap) jobBootstrap).schedule();\n        } else {\n            ((OneOffJobBootstrap) jobBootstrap).execute();\n        }\n    }\n    \n    @AfterEach\n    void tearDown() {\n        jobBootstrap.shutdown();\n        ReflectionUtils.setFieldValue(JobRegistry.getInstance(), \"instance\", null);\n    }\n    \n    public enum TestType {\n        \n        SCHEDULE, ONE_OFF\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/disable/DisabledJobE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.disable;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.env.IpUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerStatus;\nimport org.apache.shardingsphere.elasticjob.test.e2e.raw.BaseE2ETest;\nimport org.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.job.E2EFixtureJobImpl;\nimport org.awaitility.Awaitility;\nimport org.hamcrest.core.IsNull;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNull;\n\npublic abstract class DisabledJobE2ETest extends BaseE2ETest {\n    \n    public DisabledJobE2ETest(final TestType type) {\n        super(type, new E2EFixtureJobImpl());\n    }\n    \n    protected final void assertDisabledRegCenterInfo() {\n        Awaitility.await().atLeast(1L, TimeUnit.MILLISECONDS).atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> {\n            assertThat(JobRegistry.getInstance().getCurrentShardingTotalCount(getJobName()), is(3));\n            assertThat(JobRegistry.getInstance().getJobInstance(getJobName()).getServerIp(), is(IpUtils.getIp()));\n        });\n        JobConfiguration jobConfig = YamlEngine.unmarshal(getRegistryCenter().get(\"/\" + getJobName() + \"/config\"), JobConfigurationPOJO.class).toJobConfiguration();\n        assertThat(jobConfig.getShardingTotalCount(), is(3));\n        if (getJobBootstrap() instanceof ScheduleJobBootstrap) {\n            assertThat(jobConfig.getCron(), is(\"0/1 * * * * ?\"));\n        } else {\n            assertNull(jobConfig.getCron());\n        }\n        assertThat(jobConfig.getShardingItemParameters(), is(\"0=A,1=B,2=C\"));\n        assertThat(getRegistryCenter().get(\"/\" + getJobName() + \"/servers/\" + JobRegistry.getInstance().getJobInstance(getJobName()).getServerIp()), is(ServerStatus.DISABLED.name()));\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> assertThat(getRegistryCenter().get(\"/\" + getJobName() + \"/leader/election/instance\"), is(IsNull.nullValue())));\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/disable/OneOffDisabledJobE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.disable;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.junit.jupiter.api.Test;\n\nclass OneOffDisabledJobE2ETest extends DisabledJobE2ETest {\n    \n    OneOffDisabledJobE2ETest() {\n        super(TestType.ONE_OFF);\n    }\n    \n    @Override\n    protected JobConfiguration getJobConfiguration(final String jobName) {\n        return JobConfiguration.newBuilder(jobName, 3).shardingItemParameters(\"0=A,1=B,2=C\")\n                .jobListenerTypes(\"INTEGRATE-TEST\", \"INTEGRATE-DISTRIBUTE\").disabled(true).overwrite(true).build();\n    }\n    \n    @Test\n    void assertJobRunning() {\n        assertDisabledRegCenterInfo();\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/disable/ScheduleDisabledJobE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.disable;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerStatus;\nimport org.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.job.E2EFixtureJobImpl;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ScheduleDisabledJobE2ETest extends DisabledJobE2ETest {\n    \n    ScheduleDisabledJobE2ETest() {\n        super(TestType.SCHEDULE);\n    }\n    \n    @Override\n    protected JobConfiguration getJobConfiguration(final String jobName) {\n        return JobConfiguration.newBuilder(jobName, 3).cron(\"0/1 * * * * ?\").shardingItemParameters(\"0=A,1=B,2=C\")\n                .jobListenerTypes(\"INTEGRATE-TEST\", \"INTEGRATE-DISTRIBUTE\").disabled(true).overwrite(true).build();\n    }\n    \n    @Test\n    void assertJobRunning() {\n        assertDisabledRegCenterInfo();\n        setJobEnable();\n        Awaitility.await().atMost(30L, TimeUnit.SECONDS).until(() -> ((E2EFixtureJobImpl) getElasticJob()).isCompleted());\n        assertEnabledRegCenterInfo();\n    }\n    \n    private void setJobEnable() {\n        getRegistryCenter().persist(\"/\" + getJobName() + \"/servers/\" + JobRegistry.getInstance().getJobInstance(getJobName()).getServerIp(), ServerStatus.ENABLED.name());\n    }\n    \n    private void assertEnabledRegCenterInfo() {\n        assertTrue(getRegistryCenter().isExisted(\"/\" + getJobName() + \"/instances/\" + JobRegistry.getInstance().getJobInstance(getJobName()).getJobInstanceId()));\n        getRegistryCenter().remove(\"/\" + getJobName() + \"/leader/election\");\n        assertTrue(getRegistryCenter().isExisted(\"/\" + getJobName() + \"/sharding\"));\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/enable/EnabledJobE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.enable;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.env.IpUtils;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.kernel.infra.yaml.YamlEngine;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.test.e2e.raw.BaseE2ETest;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.server.ServerStatus;\nimport org.junit.jupiter.api.BeforeEach;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\npublic abstract class EnabledJobE2ETest extends BaseE2ETest {\n    \n    protected EnabledJobE2ETest(final TestType type, final ElasticJob elasticJob) {\n        super(type, elasticJob);\n    }\n    \n    @BeforeEach\n    void assertEnabledRegCenterInfo() {\n        assertThat(JobRegistry.getInstance().getCurrentShardingTotalCount(getJobName()), is(3));\n        assertThat(JobRegistry.getInstance().getJobInstance(getJobName()).getServerIp(), is(IpUtils.getIp()));\n        JobConfiguration jobConfig = YamlEngine.unmarshal(getRegistryCenter().get(\"/\" + getJobName() + \"/config\"), JobConfigurationPOJO.class).toJobConfiguration();\n        assertThat(jobConfig.getShardingTotalCount(), is(3));\n        if (getJobBootstrap() instanceof ScheduleJobBootstrap) {\n            assertThat(jobConfig.getCron(), is(\"0/1 * * * * ?\"));\n        } else {\n            assertNull(jobConfig.getCron());\n        }\n        assertThat(jobConfig.getShardingItemParameters(), is(\"0=A,1=B,2=C\"));\n        assertThat(getRegistryCenter().get(\"/\" + getJobName() + \"/servers/\" + JobRegistry.getInstance().getJobInstance(getJobName()).getServerIp()), is(ServerStatus.ENABLED.name()));\n        assertThat(getRegistryCenter().get(\"/\" + getJobName() + \"/leader/election/instance\"), is(JobRegistry.getInstance().getJobInstance(getJobName()).getJobInstanceId()));\n        assertTrue(getRegistryCenter().isExisted(\"/\" + getJobName() + \"/instances/\" + JobRegistry.getInstance().getJobInstance(getJobName()).getJobInstanceId()));\n        getRegistryCenter().remove(\"/\" + getJobName() + \"/leader/election\");\n        assertTrue(getLeaderService().isLeaderUntilBlock());\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/enable/OneOffEnabledJobE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.enable;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.job.E2EFixtureJobImpl;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass OneOffEnabledJobE2ETest extends EnabledJobE2ETest {\n    \n    OneOffEnabledJobE2ETest() {\n        super(TestType.ONE_OFF, new E2EFixtureJobImpl());\n    }\n    \n    @Override\n    protected JobConfiguration getJobConfiguration(final String jobName) {\n        return JobConfiguration.newBuilder(jobName, 3).shardingItemParameters(\"0=A,1=B,2=C\")\n                .jobListenerTypes(\"INTEGRATE-TEST\", \"INTEGRATE-DISTRIBUTE\").overwrite(true).build();\n    }\n    \n    @Test\n    void assertJobInit() {\n        Awaitility.await().atMost(1L, TimeUnit.MINUTES).untilAsserted(() -> assertThat(((E2EFixtureJobImpl) getElasticJob()).isCompleted(), is(true)));\n        assertTrue(getRegistryCenter().isExisted(\"/\" + getJobName() + \"/sharding\"));\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/enable/ScheduleEnabledJobE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.enable;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.job.E2EFixtureJobImpl;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.Test;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.junit.jupiter.api.Assertions.assertTrue;\n\nclass ScheduleEnabledJobE2ETest extends EnabledJobE2ETest {\n    \n    ScheduleEnabledJobE2ETest() {\n        super(TestType.SCHEDULE, new E2EFixtureJobImpl());\n    }\n    \n    @Override\n    protected JobConfiguration getJobConfiguration(final String jobName) {\n        return JobConfiguration.newBuilder(jobName, 3).cron(\"0/1 * * * * ?\").shardingItemParameters(\"0=A,1=B,2=C\")\n                .jobListenerTypes(\"INTEGRATE-TEST\", \"INTEGRATE-DISTRIBUTE\").overwrite(true).build();\n    }\n    \n    @Test\n    void assertJobInit() {\n        Awaitility.await().atMost(10L, TimeUnit.SECONDS).untilAsserted(() -> assertThat(((E2EFixtureJobImpl) getElasticJob()).isCompleted(), is(true)));\n        assertTrue(getRegistryCenter().isExisted(\"/\" + getJobName() + \"/sharding\"));\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/fixture/executor/E2EFixtureJobExecutor.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.executor;\n\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.JobRuntimeService;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor;\nimport org.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.job.E2EFixtureJob;\n\npublic final class E2EFixtureJobExecutor implements ClassedJobItemExecutor<E2EFixtureJob> {\n    \n    @Override\n    public void process(final E2EFixtureJob elasticJob, final JobConfiguration jobConfig, final JobRuntimeService jobRuntimeService, final ShardingContext shardingContext) {\n        elasticJob.foo(shardingContext);\n    }\n    \n    @Override\n    public Class<E2EFixtureJob> getElasticJobClass() {\n        return E2EFixtureJob.class;\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/fixture/job/E2EFixtureJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.job;\n\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\npublic interface E2EFixtureJob extends ElasticJob {\n    \n    /**\n     * Do job.\n     *\n     * @param shardingContext sharding context\n     */\n    void foo(ShardingContext shardingContext);\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/fixture/job/E2EFixtureJobImpl.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.job;\n\nimport lombok.Getter;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\n\nimport java.util.Collection;\nimport java.util.concurrent.CopyOnWriteArraySet;\n\npublic final class E2EFixtureJobImpl implements E2EFixtureJob {\n    \n    private final Collection<Integer> completedJobItems = new CopyOnWriteArraySet<>();\n    \n    @Getter\n    private volatile boolean completed;\n    \n    @Override\n    public void foo(final ShardingContext shardingContext) {\n        completedJobItems.add(shardingContext.getShardingItem());\n        completed = completedJobItems.size() == shardingContext.getShardingTotalCount();\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/fixture/listener/DistributeOnceE2EFixtureJobListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\nimport org.apache.shardingsphere.elasticjob.kernel.listener.AbstractDistributeOnceElasticJobListener;\n\npublic class DistributeOnceE2EFixtureJobListener extends AbstractDistributeOnceElasticJobListener {\n    \n    public DistributeOnceE2EFixtureJobListener() {\n        super(100L, 100L);\n    }\n    \n    @Override\n    public void doBeforeJobExecutedAtLastStarted(final ShardingContexts shardingContexts) {\n    }\n    \n    @Override\n    public void doAfterJobExecutedAtLastCompleted(final ShardingContexts shardingContexts) {\n    }\n    \n    @Override\n    public String getType() {\n        return \"INTEGRATE-DISTRIBUTE\";\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/raw/fixture/listener/E2EFixtureJobListener.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.listener;\n\nimport org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener;\nimport org.apache.shardingsphere.elasticjob.spi.listener.param.ShardingContexts;\n\npublic class E2EFixtureJobListener implements ElasticJobListener {\n    \n    @Override\n    public void beforeJobExecuted(final ShardingContexts shardingContexts) {\n    }\n    \n    @Override\n    public void afterJobExecuted(final ShardingContexts shardingContexts) {\n    }\n    \n    @Override\n    public String getType() {\n        return \"INTEGRATE-TEST\";\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/snapshot/BaseSnapshotServiceE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.snapshot;\n\nimport lombok.AccessLevel;\nimport lombok.Getter;\nimport org.apache.curator.test.InstanceSpec;\nimport org.apache.shardingsphere.elasticjob.api.ElasticJob;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.schedule.JobRegistry;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.test.util.EmbedTestingServer;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\n\npublic abstract class BaseSnapshotServiceE2ETest {\n    \n    static final int DUMP_PORT = InstanceSpec.getRandomPort();\n    \n    private static final EmbedTestingServer EMBED_TESTING_SERVER = new EmbedTestingServer();\n    \n    @Getter(value = AccessLevel.PROTECTED)\n    private static CoordinatorRegistryCenter regCenter;\n    \n    @Getter(value = AccessLevel.PROTECTED)\n    private static SnapshotService snapshotService;\n    \n    private final ScheduleJobBootstrap bootstrap;\n    \n    @Getter(value = AccessLevel.PROTECTED)\n    private final String jobName = System.nanoTime() + \"_test_job\";\n    \n    public BaseSnapshotServiceE2ETest(final ElasticJob elasticJob) {\n        bootstrap = new ScheduleJobBootstrap(regCenter, elasticJob, JobConfiguration.newBuilder(jobName, 3).cron(\"0/1 * * * * ?\").overwrite(true).build());\n    }\n    \n    @BeforeAll\n    static void init() {\n        EMBED_TESTING_SERVER.start();\n        ZookeeperConfiguration zookeeperConfig = new ZookeeperConfiguration(EMBED_TESTING_SERVER.getConnectionString(), \"zkRegTestCenter\");\n        regCenter = new ZookeeperRegistryCenter(zookeeperConfig);\n        snapshotService = new SnapshotService(regCenter, DUMP_PORT);\n        zookeeperConfig.setConnectionTimeoutMilliseconds(30000);\n        regCenter.init();\n    }\n    \n    @BeforeEach\n    void setUp() {\n        regCenter.init();\n        bootstrap.schedule();\n    }\n    \n    @AfterEach\n    void tearDown() {\n        bootstrap.shutdown();\n        ReflectionUtils.setFieldValue(JobRegistry.getInstance(), \"instance\", null);\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/snapshot/SnapshotServiceDisableE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.snapshot;\n\nimport org.apache.curator.test.InstanceSpec;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService;\nimport org.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.job.E2EFixtureJobImpl;\nimport org.apache.shardingsphere.elasticjob.test.util.ReflectionUtils;\nimport org.junit.jupiter.api.Test;\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\n\nimport static org.junit.jupiter.api.Assertions.assertNull;\nimport static org.junit.jupiter.api.Assertions.assertThrows;\n\nclass SnapshotServiceDisableE2ETest extends BaseSnapshotServiceE2ETest {\n    \n    SnapshotServiceDisableE2ETest() {\n        super(new E2EFixtureJobImpl());\n    }\n    \n    @Test\n    void assertMonitorWithDumpCommand() {\n        assertThrows(IOException.class, () -> SocketUtils.sendCommand(SnapshotService.DUMP_COMMAND, DUMP_PORT - 1));\n    }\n    \n    @Test\n    void assertPortInvalid() {\n        assertThrows(IllegalArgumentException.class, () -> new SnapshotService(getRegCenter(), -1).listen());\n    }\n    \n    @Test\n    void assertListenException() throws IOException {\n        int randomPort = InstanceSpec.getRandomPort();\n        ServerSocket serverSocket = new ServerSocket(randomPort);\n        SnapshotService snapshotService = new SnapshotService(getRegCenter(), randomPort);\n        snapshotService.listen();\n        serverSocket.close();\n        assertNull(ReflectionUtils.getFieldValue(snapshotService, \"serverSocket\"));\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/snapshot/SnapshotServiceEnableE2ETest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.snapshot;\n\nimport org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService;\nimport org.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.job.E2EFixtureJobImpl;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport java.io.IOException;\n\nimport static org.junit.jupiter.api.Assertions.assertEquals;\nimport static org.junit.jupiter.api.Assertions.assertNotNull;\n\nclass SnapshotServiceEnableE2ETest extends BaseSnapshotServiceE2ETest {\n    \n    SnapshotServiceEnableE2ETest() {\n        super(new E2EFixtureJobImpl());\n    }\n    \n    @BeforeEach\n    void listenMonitor() {\n        getSnapshotService().listen();\n    }\n    \n    @AfterEach\n    void closeMonitor() {\n        getSnapshotService().close();\n    }\n    \n    @Test\n    void assertMonitorWithCommand() throws IOException {\n        assertNotNull(SocketUtils.sendCommand(SnapshotService.DUMP_COMMAND + getJobName(), DUMP_PORT));\n        assertEquals(SocketUtils.sendCommand(\"unknown_command\", DUMP_PORT), \"\");\n    }\n    \n    @Test\n    void assertDumpJobDirectly() {\n        assertNotNull(getSnapshotService().dumpJobDirectly(getJobName()));\n    }\n    \n    @Test\n    void assertDumpJob() throws IOException {\n        assertNotNull(SnapshotService.dumpJob(\"127.0.0.1\", DUMP_PORT, getJobName()));\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/java/org/apache/shardingsphere/elasticjob/test/e2e/snapshot/SocketUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.e2e.snapshot;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.net.Socket;\n\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class SocketUtils {\n    \n    /**\n     * Send command.\n     *\n     * @param command command\n     * @param dumpPort the port for dumping data\n     * @return result of command\n     * @throws IOException io exception\n     */\n    public static String sendCommand(final String command, final int dumpPort) throws IOException {\n        try (\n                Socket socket = new Socket(\"127.0.0.1\", dumpPort);\n                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))) {\n            writer.write(command);\n            writer.newLine();\n            writer.flush();\n            StringBuilder sb = new StringBuilder();\n            String line;\n            while (null != (line = reader.readLine())) {\n                sb.append(line).append(\"\\n\");\n            }\n            return sb.toString();\n        }\n    }\n}\n"
  },
  {
    "path": "test/e2e/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.executor.item.type.ClassedJobItemExecutor",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.executor.E2EFixtureJobExecutor\n"
  },
  {
    "path": "test/e2e/src/test/resources/META-INF/services/org.apache.shardingsphere.elasticjob.spi.listener.ElasticJobListener",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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\norg.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.listener.DistributeOnceE2EFixtureJobListener\norg.apache.shardingsphere.elasticjob.test.e2e.raw.fixture.listener.E2EFixtureJobListener\n"
  },
  {
    "path": "test/e2e/src/test/resources/logback-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<configuration>\n    <property name=\"log.context.name\" value=\"elasticjob-test\" />\n    <property name=\"log.charset\" value=\"UTF-8\" />\n    <property name=\"log.pattern\" value=\"[%-5level] %date --%thread-- [%logger] %msg %n\" />\n    \n    <contextName>${log.context.name}</contextName>\n    \n    <statusListener class=\"ch.qos.logback.core.status.NopStatusListener\" />\n    \n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <filter class=\"ch.qos.logback.classic.filter.ThresholdFilter\">\n            <level>ERROR</level>\n        </filter>\n        <encoder charset=\"${log.charset}\">\n            <pattern>${log.pattern}</pattern>\n        </encoder>\n    </appender>\n    \n    <root>\n        <appender-ref ref=\"STDOUT\" />\n    </root>\n    \n    <logger name=\"org.apache.shardingsphere.elasticjob.kernel.internal.snapshot.SnapshotService\" level=\"OFF\" />\n    <logger name=\"org.apache.curator.framework.listen.MappingListenerManager\" level=\"OFF\" />\n</configuration>\n"
  },
  {
    "path": "test/native/native-image-filter/extra-filter.json",
    "content": "{\n  \"rules\": [\n    {\"includeClasses\": \"**\"},\n\n    {\"excludeClasses\": \"com.**\"},\n    {\"excludeClasses\": \"java.**\"},\n    {\"includeClasses\": \"java.util.Properties\"},\n    {\"excludeClasses\": \"javax.**\"},\n    {\"excludeClasses\": \"org.**\"},\n    {\"includeClasses\": \"org.apache.shardingsphere.elasticjob.**\"},\n    {\"excludeClasses\": \"sun.**\"},\n\n    {\"excludeClasses\": \"org.apache.shardingsphere.elasticjob.test.natived.**\"}\n  ],\n  \"regexRules\": [\n  ]\n}\n"
  },
  {
    "path": "test/native/native-image-filter/user-code-filter.json",
    "content": "{\n  \"rules\": [\n    {\"excludeClasses\": \"**\"},\n    {\"includeClasses\": \"org.apache.shardingsphere.elasticjob.**\"},\n    {\"excludeClasses\": \"org.apache.shardingsphere.elasticjob.test.natived.**\"}\n  ]\n}\n"
  },
  {
    "path": "test/native/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-test</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-test-native</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <properties>\n        <maven.deploy.skip>true</maven.deploy.skip>\n        <!--TODO Blocked by https://github.com/apache/shardingsphere-elasticjob/issues/2425 -->\n        <spring-boot-dependencies.version>3.5.5</spring-boot-dependencies.version>\n        <slf4j.version>2.0.17</slf4j.version>\n        <logback.version>1.5.18</logback.version>\n    </properties>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-spring-boot-starter</artifactId>\n            <version>${project.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shardingsphere.elasticjob</groupId>\n            <artifactId>elasticjob-lifecycle</artifactId>\n            <version>${project.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.awaitility</groupId>\n            <artifactId>awaitility</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n            <version>${spring-boot-dependencies.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <version>${spring-boot-dependencies.version}</version>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <version>${spring-boot-dependencies.version}</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    \n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.graalvm.buildtools</groupId>\n                <artifactId>native-maven-plugin</artifactId>\n                <version>${native-maven-plugin.version}</version>\n            </plugin>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>${spring-boot-dependencies.version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/TestMain.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot Web Server for testing only.\n */\n@SpringBootApplication\npublic class TestMain {\n    \n    // CHECKSTYLE:OFF\n    public static void main(final String[] args) {\n        // CHECKSTYLE:ON\n        SpringApplication.run(TestMain.class, args);\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/commons/controller/OneOffJobController.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.commons.controller;\n\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.Objects;\n\n@RestController\npublic class OneOffJobController {\n    \n    @SuppressWarnings(\"SpringJavaInjectionPointsAutowiringInspection\")\n    @Autowired\n    @Qualifier(\"manualScriptJobBean\")\n    private ObjectProvider<OneOffJobBootstrap> manualScriptJobProvider;\n    \n    /**\n     * Execute manual script job.\n     *\n     * @return a String\n     */\n    @GetMapping(\"/execute/manualScriptJob\")\n    public String executeManualScriptJob() {\n        OneOffJobBootstrap manualScriptJob = manualScriptJobProvider.getIfAvailable();\n        Objects.requireNonNull(manualScriptJob);\n        manualScriptJob.execute();\n        manualScriptJob.shutdown();\n        return \"{\\\"msg\\\":\\\"OK\\\"}\";\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/commons/entity/Foo.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.commons.entity;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Getter;\nimport lombok.Setter;\nimport lombok.ToString;\n\nimport java.io.Serializable;\n\n@Getter\n@ToString\n@AllArgsConstructor\npublic final class Foo implements Serializable {\n    \n    private static final long serialVersionUID = 2706842871078949451L;\n    \n    private final long id;\n    \n    private final String location;\n    \n    @Setter\n    private Status status;\n    \n    public enum Status {\n        UNFINISHED,\n        COMPLETED\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/commons/job/dataflow/JavaDataflowJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.commons.job.dataflow;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.entity.Foo;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.repository.FooRepository;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.repository.FooRepositoryFactory;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\npublic class JavaDataflowJob implements DataflowJob<Foo> {\n    \n    private final FooRepository fooRepository = FooRepositoryFactory.getFOO_REPOSITORY();\n    \n    @Override\n    public List<Foo> fetchData(final ShardingContext shardingContext) {\n        System.out.printf(\n                \"Item: %s | Time: %s | Thread: %s | %s%n\",\n                shardingContext.getShardingItem(),\n                new SimpleDateFormat(\"HH:mm:ss\").format(new Date()),\n                Thread.currentThread().getId(),\n                \"DATAFLOW FETCH\");\n        return fooRepository.findUnfinishedData(shardingContext.getShardingParameter(), 10);\n    }\n    \n    @Override\n    public void processData(final ShardingContext shardingContext, final List<Foo> data) {\n        System.out.printf(\n                \"Item: %s | Time: %s | Thread: %s | %s%n\",\n                shardingContext.getShardingItem(),\n                new SimpleDateFormat(\"HH:mm:ss\").format(new Date()),\n                Thread.currentThread().getId(),\n                \"DATAFLOW PROCESS\");\n        data.stream().mapToLong(Foo::getId).forEach(fooRepository::setCompleted);\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/commons/job/dataflow/SpringBootDataflowJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.commons.job.dataflow;\n\nimport org.apache.shardingsphere.elasticjob.dataflow.job.DataflowJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.entity.Foo;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.repository.SpringBootFooRepository;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.lang.invoke.MethodHandles;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\n@SuppressWarnings(\"LoggingSimilarMessage\")\n@Component\npublic class SpringBootDataflowJob implements DataflowJob<Foo> {\n    \n    private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());\n    \n    @Autowired\n    private SpringBootFooRepository springBootFooRepository;\n    \n    @Override\n    public List<Foo> fetchData(final ShardingContext shardingContext) {\n        logger.info(\"Item: {} | Time: {} | Thread: {} | {}\",\n                shardingContext.getShardingItem(),\n                new SimpleDateFormat(\"HH:mm:ss\").format(new Date()),\n                Thread.currentThread().getId(),\n                \"DATAFLOW FETCH\");\n        return springBootFooRepository.findUnfinishedData(shardingContext.getShardingParameter(), 10);\n    }\n    \n    @Override\n    public void processData(final ShardingContext shardingContext, final List<Foo> data) {\n        logger.info(\"Item: {} | Time: {} | Thread: {} | {}\",\n                shardingContext.getShardingItem(),\n                new SimpleDateFormat(\"HH:mm:ss\").format(new Date()),\n                Thread.currentThread().getId(),\n                \"DATAFLOW PROCESS\");\n        data.forEach(each -> springBootFooRepository.setCompleted(each.getId()));\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/commons/job/simple/JavaSimpleJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.commons.job.simple;\n\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.entity.Foo;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.repository.FooRepository;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.repository.FooRepositoryFactory;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\npublic class JavaSimpleJob implements SimpleJob {\n    \n    private final FooRepository fooRepository = FooRepositoryFactory.getFOO_REPOSITORY();\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        System.out.printf(\n                \"Item: %s | Time: %s | Thread: %s | %s%n\",\n                shardingContext.getShardingItem(),\n                new SimpleDateFormat(\"HH:mm:ss\").format(new Date()),\n                Thread.currentThread().getId(),\n                \"SIMPLE\");\n        List<Foo> data = fooRepository.findUnfinishedData(shardingContext.getShardingParameter(), 10);\n        data.stream().mapToLong(Foo::getId).forEach(fooRepository::setCompleted);\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/commons/job/simple/SpringBootSimpleJob.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.commons.job.simple;\n\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.apache.shardingsphere.elasticjob.spi.executor.item.param.ShardingContext;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.repository.SpringBootFooRepository;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.lang.invoke.MethodHandles;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n@Component\npublic class SpringBootSimpleJob implements SimpleJob {\n    \n    private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());\n    \n    @Autowired\n    private SpringBootFooRepository springBootFooRepository;\n    \n    @Override\n    public void execute(final ShardingContext shardingContext) {\n        logger.info(\n                \"Item: {} | Time: {} | Thread: {} | {}\",\n                shardingContext.getShardingItem(),\n                new SimpleDateFormat(\"HH:mm:ss\").format(new Date()),\n                Thread.currentThread().getId(),\n                \"SIMPLE\");\n        springBootFooRepository.findUnfinishedData(shardingContext.getShardingParameter(), 10)\n                .forEach(each -> springBootFooRepository.setCompleted(each.getId()));\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/commons/repository/FooRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.commons.repository;\n\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.entity.Foo;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.LongStream;\n\npublic class FooRepository {\n    \n    private final Map<Long, Foo> data = new ConcurrentHashMap<>(300, 1);\n    \n    public FooRepository() {\n        addData(0L, 100L, \"Norddorf\");\n        addData(100L, 200L, \"Bordeaux\");\n        addData(200L, 300L, \"Somerset\");\n    }\n    \n    private void addData(final long idFrom, final long idTo, final String location) {\n        LongStream.range(idFrom, idTo)\n                .forEachOrdered(i -> data.put(i, new Foo(i, location, Foo.Status.UNFINISHED)));\n    }\n    \n    /**\n     * Find Unfinished Data.\n     * @param location location\n     * @param limit limit\n     * @return An ordered collection, where the user has precise control over where in the list each element is inserted.\n     */\n    public List<Foo> findUnfinishedData(final String location, final int limit) {\n        List<Foo> result = new ArrayList<>(limit);\n        int count = 0;\n        for (Map.Entry<Long, Foo> each : data.entrySet()) {\n            Foo foo = each.getValue();\n            if (foo.getLocation().equals(location) && foo.getStatus() == Foo.Status.UNFINISHED) {\n                result.add(foo);\n                count++;\n                if (count == limit) {\n                    break;\n                }\n            }\n        }\n        return result;\n    }\n    \n    /**\n     * Set completed.\n     * @param id id\n     */\n    public void setCompleted(final long id) {\n        data.get(id).setStatus(Foo.Status.COMPLETED);\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/commons/repository/FooRepositoryFactory.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.commons.repository;\n\nimport lombok.Getter;\n\npublic final class FooRepositoryFactory {\n    \n    @Getter\n    private static final FooRepository FOO_REPOSITORY = new FooRepository();\n    \n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/commons/repository/SpringBootFooRepository.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.commons.repository;\n\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.entity.Foo;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.LongStream;\n\n@Repository\npublic class SpringBootFooRepository {\n    \n    private final Map<Long, Foo> data = new ConcurrentHashMap<>(300, 1);\n    \n    public SpringBootFooRepository() {\n        addData(0L, 100L, \"Norddorf\");\n        addData(100L, 200L, \"Bordeaux\");\n        addData(200L, 300L, \"Somerset\");\n    }\n    \n    private void addData(final long idFrom, final long idTo, final String location) {\n        LongStream.range(idFrom, idTo)\n                .forEachOrdered(i -> data.put(i, new Foo(i, location, Foo.Status.UNFINISHED)));\n    }\n    \n    /**\n     * Find Unfinished Data.\n     * @param location location\n     * @param limit limit\n     * @return An ordered collection, where the user has precise control over where in the list each element is inserted.\n     */\n    public List<Foo> findUnfinishedData(final String location, final int limit) {\n        List<Foo> result = new ArrayList<>(limit);\n        int count = 0;\n        for (Map.Entry<Long, Foo> each : data.entrySet()) {\n            Foo foo = each.getValue();\n            if (foo.getLocation().equals(location) && foo.getStatus() == Foo.Status.UNFINISHED) {\n                result.add(foo);\n                count++;\n                if (count == limit) {\n                    break;\n                }\n            }\n        }\n        return result;\n    }\n    \n    /**\n     * Set completed.\n     * @param id id\n     */\n    public void setCompleted(final long id) {\n        data.get(id).setStatus(Foo.Status.COMPLETED);\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/it/operation/JavaTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.it.operation;\n\nimport com.zaxxer.hikari.HikariConfig;\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.curator.CuratorZookeeperClient;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.test.TestingServer;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.kernel.internal.config.JobConfigurationPOJO;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.JobConfigurationAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.JobOperateAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.JobStatisticsAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.ServerStatisticsAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.ShardingOperateAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.api.ShardingStatisticsAPI;\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.JobBriefInfo;\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.ServerBriefInfo;\nimport org.apache.shardingsphere.elasticjob.lifecycle.domain.ShardingInfo;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.operate.JobOperateAPIImpl;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.operate.ShardingOperateAPIImpl;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.settings.JobConfigurationAPIImpl;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.JobStatisticsAPIImpl;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.ServerStatisticsAPIImpl;\nimport org.apache.shardingsphere.elasticjob.lifecycle.internal.statistics.ShardingStatisticsAPIImpl;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.job.simple.JavaSimpleJob;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledInNativeImage;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\nimport static org.hamcrest.Matchers.not;\nimport static org.hamcrest.Matchers.notNullValue;\nimport static org.hamcrest.Matchers.nullValue;\nimport static org.hamcrest.Matchers.startsWith;\nimport static org.junit.jupiter.api.Assertions.assertDoesNotThrow;\n\n@EnabledInNativeImage\nclass JavaTest {\n    \n    private static TestingServer testingServer;\n    \n    private static CoordinatorRegistryCenter firstRegCenter;\n    \n    private static CoordinatorRegistryCenter secondRegCenter;\n    \n    private static TracingConfiguration<DataSource> tracingConfig;\n    \n    @BeforeEach\n    void beforeEach() throws Exception {\n        testingServer = new TestingServer();\n        try (\n                CuratorZookeeperClient client = new CuratorZookeeperClient(testingServer.getConnectString(),\n                        60 * 1000, 500, null,\n                        new ExponentialBackoffRetry(500, 3, 500 * 3))) {\n            client.start();\n            Awaitility.await().atMost(Duration.ofMillis(500 * 60)).ignoreExceptions().until(client::isConnected);\n        }\n        firstRegCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(testingServer.getConnectString(), \"elasticjob-test-native-operation-java\"));\n        firstRegCenter.init();\n        secondRegCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(testingServer.getConnectString(), \"elasticjob-test-native-operation-java\"));\n        secondRegCenter.init();\n        HikariConfig config = new HikariConfig();\n        config.setDriverClassName(\"org.h2.Driver\");\n        config.setJdbcUrl(\"jdbc:h2:mem:job_event_storage\");\n        config.setUsername(\"sa\");\n        config.setPassword(\"\");\n        tracingConfig = new TracingConfiguration<>(\"RDB\", new HikariDataSource(config));\n    }\n    \n    @AfterEach\n    void afterEach() throws IOException {\n        firstRegCenter.close();\n        secondRegCenter.close();\n        testingServer.close();\n    }\n    \n    /**\n     * TODO Executing {@link JobConfigurationAPI#removeJobConfiguration(String)} will always cause the listener\n     *  to throw an exception. This is not acceptable behavior.\n     *  <pre>\n     *   <code>\n     *  Caused by: java.lang.IllegalStateException: Expected state [STARTED] was [STOPPED]\n     *  at org.apache.curator.shaded.com.google.common.base.Preconditions.checkState(Preconditions.java:835)\n     *  at org.apache.curator.framework.imps.CuratorFrameworkImpl.checkState(CuratorFrameworkImpl.java:465)\n     *  at org.apache.curator.framework.imps.CuratorFrameworkImpl.getData(CuratorFrameworkImpl.java:498)\n     *  at org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter.getDirectly(ZookeeperRegistryCenter.java:179)\n     *  ... 12 common frames omitted\n     *   </code>\n     *  </pre>\n     *\n     */\n    @Test\n    void testJobConfigurationAPI() {\n        String jobName = \"testJobConfigurationAPI\";\n        ScheduleJobBootstrap job = new ScheduleJobBootstrap(firstRegCenter, new JavaSimpleJob(),\n                JobConfiguration.newBuilder(jobName, 3)\n                        .cron(\"0/5 * * * * ?\")\n                        .shardingItemParameters(\"0=Norddorf,1=Bordeaux,2=Somerset\")\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        job.schedule();\n        JobConfigurationAPI jobConfigAPI = new JobConfigurationAPIImpl(secondRegCenter);\n        JobConfigurationPOJO jobConfig = jobConfigAPI.getJobConfiguration(jobName);\n        assertThat(jobConfig, notNullValue());\n        assertThat(jobConfig.getJobName(), is(jobName));\n        assertThat(jobConfig.getCron(), is(\"0/5 * * * * ?\"));\n        assertThat(jobConfig.getShardingItemParameters(), is(\"0=Norddorf,1=Bordeaux,2=Somerset\"));\n        JobConfigurationPOJO newJobConfig = new JobConfigurationPOJO();\n        newJobConfig.setJobName(jobConfig.getJobName());\n        newJobConfig.setShardingTotalCount(jobConfig.getShardingTotalCount());\n        newJobConfig.setCron(\"0/10 * * * * ?\");\n        newJobConfig.setShardingItemParameters(jobConfig.getShardingItemParameters());\n        newJobConfig.setJobExtraConfigurations(jobConfig.getJobExtraConfigurations());\n        jobConfigAPI.updateJobConfiguration(newJobConfig);\n        JobConfigurationPOJO newTestJavaSimpleJob = jobConfigAPI.getJobConfiguration(jobName);\n        assertThat(newTestJavaSimpleJob, notNullValue());\n        assertThat(newTestJavaSimpleJob.getCron(), is(\"0/10 * * * * ?\"));\n        jobConfigAPI.removeJobConfiguration(jobName);\n        assertThat(jobConfigAPI.getJobConfiguration(jobName), nullValue());\n        job.shutdown();\n    }\n    \n    /**\n     * TODO The most embarrassing thing is that there seems to be no simple logic to\n     *  test {@link JobOperateAPI#trigger(String)} and {@link JobOperateAPI#dump(String, String, int)}.\n     */\n    @Test\n    void testJobOperateAPI() {\n        String jobName = \"testJobOperateAPI\";\n        ScheduleJobBootstrap job = new ScheduleJobBootstrap(firstRegCenter, new JavaSimpleJob(),\n                JobConfiguration.newBuilder(jobName, 3)\n                        .cron(\"0/5 * * * * ?\")\n                        .shardingItemParameters(\"0=Norddorf,1=Bordeaux,2=Somerset\")\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        job.schedule();\n        List<ServerBriefInfo> serverBriefInfos = new ArrayList<>(new ServerStatisticsAPIImpl(secondRegCenter).getAllServersBriefInfo());\n        assertThat(serverBriefInfos.size(), is(1));\n        String serverIp = serverBriefInfos.get(0).getServerIp();\n        JobOperateAPI jobOperateAPI = new JobOperateAPIImpl(secondRegCenter);\n        jobOperateAPI.disable(jobName, serverIp);\n        JobStatisticsAPIImpl jobStatisticsAPI = new JobStatisticsAPIImpl(secondRegCenter);\n        JobBriefInfo firstJobBriefInfo = jobStatisticsAPI.getJobBriefInfo(jobName);\n        assertThat(firstJobBriefInfo, notNullValue());\n        assertThat(firstJobBriefInfo.getStatus(), is(JobBriefInfo.JobStatus.DISABLED));\n        jobOperateAPI.enable(jobName, serverIp);\n        JobBriefInfo secondJobBriefInfo = jobStatisticsAPI.getJobBriefInfo(jobName);\n        assertThat(secondJobBriefInfo, notNullValue());\n        assertThat(secondJobBriefInfo.getStatus(), is(JobBriefInfo.JobStatus.SHARDING_FLAG));\n        jobOperateAPI.remove(jobName, serverIp);\n        JobBriefInfo thirdJobBriefInfo = jobStatisticsAPI.getJobBriefInfo(jobName);\n        assertThat(thirdJobBriefInfo, notNullValue());\n        assertThat(thirdJobBriefInfo.getStatus(), is(JobBriefInfo.JobStatus.CRASHED));\n        job.shutdown();\n    }\n    \n    @Test\n    void testShardingOperateAPI() {\n        String jobName = \"testShardingOperateAPI\";\n        ScheduleJobBootstrap job = new ScheduleJobBootstrap(firstRegCenter, new JavaSimpleJob(),\n                JobConfiguration.newBuilder(jobName, 3)\n                        .cron(\"0/5 * * * * ?\")\n                        .shardingItemParameters(\"0=Norddorf,1=Bordeaux,2=Somerset\")\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        job.schedule();\n        ShardingOperateAPI shardingOperateAPI = new ShardingOperateAPIImpl(secondRegCenter);\n        shardingOperateAPI.disable(jobName, \"0\");\n        ShardingStatisticsAPI shardingStatisticsAPI = new ShardingStatisticsAPIImpl(secondRegCenter);\n        List<ShardingInfo> firstShardingInfos = shardingStatisticsAPI.getShardingInfo(jobName)\n                .stream()\n                .filter(shardingInfo -> 0 == shardingInfo.getItem())\n                .collect(Collectors.toList());\n        assertThat(firstShardingInfos.size(), is(1));\n        assertThat(firstShardingInfos.get(0).getStatus(), is(ShardingInfo.ShardingStatus.DISABLED));\n        shardingOperateAPI.enable(jobName, \"0\");\n        List<ShardingInfo> secondShardingInfos = shardingStatisticsAPI.getShardingInfo(jobName)\n                .stream()\n                .filter(shardingInfo -> 0 == shardingInfo.getItem())\n                .collect(Collectors.toList());\n        assertThat(secondShardingInfos.size(), is(1));\n        assertThat(secondShardingInfos.get(0).getStatus(), is(ShardingInfo.ShardingStatus.SHARDING_FLAG));\n        job.shutdown();\n    }\n    \n    @Test\n    void testJobStatisticsAPI() {\n        String jobName = \"testJobStatisticsAPI\";\n        ScheduleJobBootstrap job = new ScheduleJobBootstrap(firstRegCenter, new JavaSimpleJob(),\n                JobConfiguration.newBuilder(jobName, 3)\n                        .cron(\"0/5 * * * * ?\")\n                        .shardingItemParameters(\"0=Norddorf,1=Bordeaux,2=Somerset\")\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        job.schedule();\n        JobStatisticsAPI jobStatisticsAPI = new JobStatisticsAPIImpl(secondRegCenter);\n        assertThat(jobStatisticsAPI.getJobsTotalCount(), is(1));\n        JobBriefInfo jobBriefInfo = jobStatisticsAPI.getJobBriefInfo(jobName);\n        assertThat(jobBriefInfo, notNullValue());\n        assertThat(jobBriefInfo.getJobName(), is(jobName));\n        assertThat(jobBriefInfo.getStatus(), is(JobBriefInfo.JobStatus.SHARDING_FLAG));\n        assertThat(jobBriefInfo.getDescription(), is(\"\"));\n        assertThat(jobBriefInfo.getCron(), is(\"0/5 * * * * ?\"));\n        assertThat(jobBriefInfo.getInstanceCount(), is(1));\n        assertThat(jobBriefInfo.getShardingTotalCount(), is(3));\n        assertThat(jobStatisticsAPI.getAllJobsBriefInfo().size(), is(1));\n        assertDoesNotThrow(() -> {\n            List<String> ipList = secondRegCenter.getChildrenKeys(\"/\" + jobName + \"/servers\");\n            assertThat(ipList.size(), is(1));\n            assertThat(jobStatisticsAPI.getJobsBriefInfo(ipList.get(0)).size(), is(1));\n        });\n        job.shutdown();\n    }\n    \n    @Test\n    void testServerStatisticsAPI() {\n        String jobName = \"testServerStatisticsAPI\";\n        ScheduleJobBootstrap job = new ScheduleJobBootstrap(firstRegCenter, new JavaSimpleJob(),\n                JobConfiguration.newBuilder(jobName, 3)\n                        .cron(\"0/5 * * * * ?\")\n                        .shardingItemParameters(\"0=Norddorf,1=Bordeaux,2=Somerset\")\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        job.schedule();\n        ServerStatisticsAPI serverStatisticsAPI = new ServerStatisticsAPIImpl(secondRegCenter);\n        assertThat(serverStatisticsAPI.getServersTotalCount(), is(1));\n        Collection<ServerBriefInfo> allServersBriefInfo = serverStatisticsAPI.getAllServersBriefInfo();\n        assertThat(allServersBriefInfo.size(), is(1));\n        allServersBriefInfo.stream().findFirst().ifPresent(serverBriefInfo -> {\n            String serverIp = serverBriefInfo.getServerIp();\n            assertThat(serverIp, notNullValue());\n            Set<String> instances = serverBriefInfo.getInstances();\n            assertThat(instances.size(), is(1));\n            assertThat(instances.stream().findFirst().isPresent(), is(true));\n            assertThat(instances.stream().findFirst().get(), startsWith(serverIp + \"@-@\"));\n            Set<String> jobNames = serverBriefInfo.getJobNames();\n            assertThat(jobNames.size(), is(1));\n            assertThat(jobNames.stream().findFirst().isPresent(), is(true));\n            assertThat(jobNames.stream().findFirst().get(), is(jobName));\n            assertThat(serverBriefInfo.getInstancesNum(), is(1));\n            assertThat(serverBriefInfo.getJobsNum(), is(1));\n            assertThat(serverBriefInfo.getDisabledJobsNum().intValue(), is(0));\n        });\n        job.shutdown();\n    }\n    \n    @Test\n    void testShardingStatisticsAPI() {\n        String jobName = \"testShardingStatisticsAPI\";\n        ScheduleJobBootstrap job = new ScheduleJobBootstrap(firstRegCenter, new JavaSimpleJob(),\n                JobConfiguration.newBuilder(jobName, 3)\n                        .cron(\"0/5 * * * * ?\")\n                        .shardingItemParameters(\"0=Norddorf,1=Bordeaux,2=Somerset\")\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        job.schedule();\n        ShardingStatisticsAPI shardingStatisticsAPI = new ShardingStatisticsAPIImpl(secondRegCenter);\n        Awaitility.await()\n                .atMost(1L, TimeUnit.MINUTES)\n                .ignoreExceptions()\n                .until(() -> 3 == shardingStatisticsAPI.getShardingInfo(jobName).size());\n        shardingStatisticsAPI.getShardingInfo(jobName).forEach(shardingInfo -> {\n            String serverIp = shardingInfo.getServerIp();\n            assertThat(serverIp, notNullValue());\n            assertThat(shardingInfo.getInstanceId(), startsWith(serverIp + \"@-@\"));\n            ShardingInfo.ShardingStatus status = shardingInfo.getStatus();\n            assertThat(status, not(ShardingInfo.ShardingStatus.SHARDING_FLAG));\n            assertThat(status, not(ShardingInfo.ShardingStatus.DISABLED));\n            assertThat(shardingInfo.isFailover(), is(false));\n        });\n        job.shutdown();\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/it/staticd/JavaTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.it.staticd;\n\nimport com.zaxxer.hikari.HikariConfig;\nimport com.zaxxer.hikari.HikariDataSource;\nimport org.apache.curator.CuratorZookeeperClient;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.test.TestingServer;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.OneOffJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.dataflow.props.DataflowJobProperties;\nimport org.apache.shardingsphere.elasticjob.http.props.HttpJobProperties;\nimport org.apache.shardingsphere.elasticjob.kernel.tracing.config.TracingConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.base.CoordinatorRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperConfiguration;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.script.props.ScriptJobProperties;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.job.dataflow.JavaDataflowJob;\nimport org.apache.shardingsphere.elasticjob.test.natived.commons.job.simple.JavaSimpleJob;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledInNativeImage;\nimport org.junit.jupiter.api.condition.EnabledOnOs;\nimport org.junit.jupiter.api.condition.OS;\n\nimport javax.sql.DataSource;\nimport java.io.IOException;\nimport java.nio.file.Paths;\nimport java.time.Duration;\n\nimport static org.junit.jupiter.api.Assertions.assertDoesNotThrow;\n\n@EnabledInNativeImage\nclass JavaTest {\n    \n    private static TestingServer testingServer;\n    \n    private static CoordinatorRegistryCenter regCenter;\n    \n    private static TracingConfiguration<DataSource> tracingConfig;\n    \n    @BeforeAll\n    static void beforeAll() throws Exception {\n        testingServer = new TestingServer();\n        try (\n                CuratorZookeeperClient client = new CuratorZookeeperClient(testingServer.getConnectString(),\n                        60 * 1000, 500, null,\n                        new ExponentialBackoffRetry(500, 3, 500 * 3))) {\n            client.start();\n            Awaitility.await().atMost(Duration.ofMillis(500 * 60)).ignoreExceptions().until(client::isConnected);\n        }\n        regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration(testingServer.getConnectString(), \"elasticjob-test-native-java\"));\n        regCenter.init();\n        HikariConfig config = new HikariConfig();\n        config.setDriverClassName(\"org.h2.Driver\");\n        config.setJdbcUrl(\"jdbc:h2:mem:job_event_storage\");\n        config.setUsername(\"sa\");\n        config.setPassword(\"\");\n        tracingConfig = new TracingConfiguration<>(\"RDB\", new HikariDataSource(config));\n    }\n    \n    @AfterAll\n    static void afterAll() throws IOException {\n        regCenter.close();\n        testingServer.close();\n    }\n    \n    @Test\n    void testHttpJob() {\n        ScheduleJobBootstrap jobBootstrap = new ScheduleJobBootstrap(regCenter, \"HTTP\",\n                JobConfiguration.newBuilder(\"testJavaHttpJob\", 3)\n                        .setProperty(HttpJobProperties.URI_KEY, \"https://www.apache.org\")\n                        .setProperty(HttpJobProperties.METHOD_KEY, \"GET\")\n                        .cron(\"0/5 * * * * ?\")\n                        .shardingItemParameters(\"0=Norddorf,1=Bordeaux,2=Somerset\")\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        assertDoesNotThrow(() -> {\n            jobBootstrap.schedule();\n            jobBootstrap.shutdown();\n        });\n    }\n    \n    @Test\n    void testSimpleJob() {\n        ScheduleJobBootstrap jobBootstrap = new ScheduleJobBootstrap(regCenter, new JavaSimpleJob(),\n                JobConfiguration.newBuilder(\"testJavaSimpleJob\", 3)\n                        .cron(\"0/5 * * * * ?\")\n                        .shardingItemParameters(\"0=Norddorf,1=Bordeaux,2=Somerset\")\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        assertDoesNotThrow(() -> {\n            jobBootstrap.schedule();\n            jobBootstrap.shutdown();\n        });\n    }\n    \n    @Test\n    void testDataflowJob() {\n        ScheduleJobBootstrap jobBootstrap = new ScheduleJobBootstrap(regCenter, new JavaDataflowJob(),\n                JobConfiguration.newBuilder(\"testJavaDataflowElasticJob\", 3)\n                        .cron(\"0/5 * * * * ?\")\n                        .shardingItemParameters(\"0=Norddorf,1=Bordeaux,2=Somerset\")\n                        .setProperty(DataflowJobProperties.STREAM_PROCESS_KEY, Boolean.TRUE.toString())\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        assertDoesNotThrow(() -> {\n            jobBootstrap.schedule();\n            jobBootstrap.shutdown();\n        });\n    }\n    \n    @Test\n    void testOneOffJob() {\n        OneOffJobBootstrap jobBootstrap = new OneOffJobBootstrap(regCenter, new JavaSimpleJob(),\n                JobConfiguration.newBuilder(\"testJavaOneOffSimpleJob\", 3)\n                        .shardingItemParameters(\"0=Norddorf,1=Bordeaux,2=Somerset\")\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        assertDoesNotThrow(() -> {\n            jobBootstrap.execute();\n            jobBootstrap.shutdown();\n        });\n    }\n    \n    @Test\n    @EnabledOnOs(OS.LINUX)\n    void testScriptJob() {\n        ScheduleJobBootstrap jobBootstrap = new ScheduleJobBootstrap(regCenter, \"SCRIPT\",\n                JobConfiguration.newBuilder(\"scriptElasticJob\", 3)\n                        .cron(\"0/5 * * * * ?\")\n                        .setProperty(ScriptJobProperties.SCRIPT_KEY, Paths.get(\"src/test/resources/test-native/sh/demo.sh\").toString())\n                        .addExtraConfigurations(tracingConfig)\n                        .build());\n        assertDoesNotThrow(() -> {\n            jobBootstrap.schedule();\n            jobBootstrap.shutdown();\n        });\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/java/org/apache/shardingsphere/elasticjob/test/natived/it/staticd/SpringBootDTest.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.natived.it.staticd;\n\nimport org.apache.curator.CuratorZookeeperClient;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.test.InstanceSpec;\nimport org.apache.curator.test.TestingServer;\nimport org.apache.shardingsphere.elasticjob.api.JobConfiguration;\nimport org.apache.shardingsphere.elasticjob.bootstrap.type.ScheduleJobBootstrap;\nimport org.apache.shardingsphere.elasticjob.reg.zookeeper.ZookeeperRegistryCenter;\nimport org.apache.shardingsphere.elasticjob.simple.job.SimpleJob;\nimport org.awaitility.Awaitility;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.condition.EnabledInNativeImage;\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.DynamicPropertyRegistry;\nimport org.springframework.test.context.DynamicPropertySource;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.request.MockMvcRequestBuilders;\nimport org.springframework.test.web.servlet.result.MockMvcResultHandlers;\nimport org.springframework.test.web.servlet.result.MockMvcResultMatchers;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.time.Duration;\nimport java.util.Objects;\n\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.hamcrest.Matchers.is;\nimport static org.junit.jupiter.api.Assertions.assertDoesNotThrow;\n\n/**\n * ElasticJob Spring Boot Starter requires that all Spring Boot Applications be shut down before shutting down Zookeeper Server.\n * That's why this unit test uses {@link DirtiesContext}.\n * Refer to <a href=\"https://github.com/spring-projects/spring-framework/issues/26196\">spring-projects/spring-framework#26196</a> .\n */\n@DirtiesContext\n@SpringBootTest(webEnvironment = org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT)\n@EnabledInNativeImage\nclass SpringBootDTest {\n    \n    private static TestingServer testingServer;\n    \n    @Autowired\n    private ObjectProvider<ZookeeperRegistryCenter> zookeeperRegistryCenterProvider;\n    \n    private MockMvc mockMvc;\n    \n    @DynamicPropertySource\n    static void elasticjobProperties(final DynamicPropertyRegistry registry) {\n        registry.add(\"elasticjob.regCenter.serverLists\", () -> testingServer.getConnectString());\n        registry.add(\"elasticjob.dump.port\", InstanceSpec::getRandomPort);\n    }\n    \n    @BeforeAll\n    static void beforeAll() throws Exception {\n        testingServer = new TestingServer();\n        try (\n                CuratorZookeeperClient client = new CuratorZookeeperClient(testingServer.getConnectString(),\n                        60 * 1000, 500, null,\n                        new ExponentialBackoffRetry(500, 3, 500 * 3))) {\n            client.start();\n            Awaitility.await().atMost(Duration.ofMillis(500 * 60)).ignoreExceptions().until(client::isConnected);\n        }\n    }\n    \n    @AfterAll\n    static void afterAll() throws IOException {\n        testingServer.close();\n    }\n    \n    @BeforeEach\n    void setup(final WebApplicationContext webApplicationContext) {\n        this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)\n                .defaultResponseCharacterEncoding(StandardCharsets.UTF_8)\n                .build();\n    }\n    \n    @Test\n    public void testOneOffJob() throws Exception {\n        String contentAsString = mockMvc.perform(\n                MockMvcRequestBuilders.get(\"/execute/manualScriptJob\")\n                        .characterEncoding(StandardCharsets.UTF_8))\n                .andDo(MockMvcResultHandlers.print())\n                .andExpectAll(\n                        MockMvcResultMatchers.status().isOk(),\n                        MockMvcResultMatchers.content().encoding(StandardCharsets.UTF_8))\n                .andReturn()\n                .getResponse()\n                .getContentAsString();\n        assertThat(contentAsString, is(\"{\\\"msg\\\":\\\"OK\\\"}\"));\n    }\n    \n    @Test\n    void testIssue2012() {\n        ZookeeperRegistryCenter zookeeperRegistryCenter = zookeeperRegistryCenterProvider.getIfAvailable();\n        Objects.requireNonNull(zookeeperRegistryCenter);\n        JobConfiguration jobConfig = JobConfiguration.newBuilder(\"test\", 1)\n                .jobParameter(\"\")\n                .cron(\"0 30 2 ? * *\")\n                .overwrite(true)\n                .jobShardingStrategyType(\"ROUND_ROBIN\")\n                .monitorExecution(true)\n                .failover(true)\n                .build();\n        ScheduleJobBootstrap firstJob = new ScheduleJobBootstrap(zookeeperRegistryCenter,\n                (SimpleJob) shardingContext -> System.out.println(\"test\"),\n                jobConfig);\n        ScheduleJobBootstrap secondJob = new ScheduleJobBootstrap(zookeeperRegistryCenter,\n                (SimpleJob) shardingContext -> System.out.println(\"test\"),\n                jobConfig);\n        assertDoesNotThrow(() -> {\n            firstJob.schedule();\n            secondJob.schedule();\n            firstJob.shutdown();\n            secondJob.shutdown();\n        });\n    }\n}\n"
  },
  {
    "path": "test/native/src/test/resources/application.yml",
    "content": "#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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# `elasticjob.regCenter.serverLists` is dynamically defined in `org.springframework.test.context.DynamicPropertySource`\n# `elasticjob.dump.port` is dynamically defined in `org.springframework.test.context.DynamicPropertySource`\nelasticjob:\n  tracing:\n    type: RDB\n    data-source:\n      url: jdbc:h2:mem:job_event_storage\n      driver-class-name: org.h2.Driver\n      username: sa\n      password:\n  regCenter:\n    namespace: elasticjob-test-native-springboot\n  jobs:\n    simpleJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.test.natived.commons.job.simple.SpringBootSimpleJob\n      cron: 0/5 * * * * ?\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Norddorf,1=Bordeaux,2=Somerset\n    dataflowJob:\n      elasticJobClass: org.apache.shardingsphere.elasticjob.test.natived.commons.job.dataflow.SpringBootDataflowJob\n      cron: 0/5 * * * * ?\n      shardingTotalCount: 3\n      shardingItemParameters: 0=Norddorf,1=Bordeaux,2=Somerset\n    scriptJob:\n      elasticJobType: SCRIPT\n      cron: 0/10 * * * * ?\n      shardingTotalCount: 3\n      props:\n        script.command.line: \"echo SCRIPT Job: \"\n    manualScriptJob:\n      elasticJobType: SCRIPT\n      jobBootstrapBeanName: manualScriptJobBean\n      shardingTotalCount: 9\n      props:\n        script.command.line: \"echo Manual SCRIPT Job: \"\n"
  },
  {
    "path": "test/native/src/test/resources/test-native/sh/demo.sh",
    "content": "#!/bin/bash\n#\n# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  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# shellcheck disable=SC2048\n# shellcheck disable=SC2086\necho Sharding Context: $*\n"
  },
  {
    "path": "test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-test</artifactId>\n    <packaging>pom</packaging>\n    <name>${project.artifactId}</name>\n    \n    <modules>\n        <module>e2e</module>\n        <module>util</module>\n    </modules>\n    \n    <profiles>\n        <!-- Block `elasticjob-test-native` module from compiling on JDK 8 to JDK16 -->\n        <profile>\n            <id>jdk17+</id>\n            <activation>\n                <jdk>[17,)</jdk>\n            </activation>\n            <modules>\n                <module>native</module>\n            </modules>\n        </profile>\n    </profiles>\n</project>\n"
  },
  {
    "path": "test/util/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Licensed to the Apache Software Foundation (ASF) under one or more\n  ~ contributor license agreements.  See the NOTICE file distributed with\n  ~ this work for additional information regarding copyright ownership.\n  ~ The ASF licenses this file to You under the Apache License, Version 2.0\n  ~ (the \"License\"); you may not use this file except in compliance with\n  ~ the License.  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<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.apache.shardingsphere.elasticjob</groupId>\n        <artifactId>elasticjob-test</artifactId>\n        <version>3.0.6-SNAPSHOT</version>\n    </parent>\n    <artifactId>elasticjob-test-util</artifactId>\n    <name>${project.artifactId}</name>\n    \n    <properties>\n        <maven.deploy.skip>true</maven.deploy.skip>\n    </properties>\n    \n    <dependencies>\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-framework</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.curator</groupId>\n            <artifactId>curator-test</artifactId>\n            <scope>compile</scope>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "test/util/src/main/java/org/apache/shardingsphere/elasticjob/test/util/EmbedTestingServer.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.util;\n\nimport lombok.AllArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.curator.framework.CuratorFramework;\nimport org.apache.curator.framework.CuratorFrameworkFactory;\nimport org.apache.curator.framework.imps.CuratorFrameworkState;\nimport org.apache.curator.retry.ExponentialBackoffRetry;\nimport org.apache.curator.test.InstanceSpec;\nimport org.apache.curator.test.TestingServer;\nimport org.apache.zookeeper.KeeperException;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Embed ZooKeeper testing server.\n */\n@AllArgsConstructor\n@Slf4j\npublic final class EmbedTestingServer {\n    \n    private static volatile TestingServer testingServer;\n    \n    private static final Object INIT_LOCK = new Object();\n    \n    private final int port;\n    \n    /**\n     * Create the server using a random port.\n     */\n    public EmbedTestingServer() {\n        port = InstanceSpec.getRandomPort();\n    }\n    \n    /**\n     * Start embed zookeeper server.\n     */\n    public void start() {\n        if (null != testingServer) {\n            log.info(\"Embed zookeeper server already exists 1, on {}\", testingServer.getConnectString());\n            return;\n        }\n        log.info(\"Starting embed zookeeper server...\");\n        synchronized (INIT_LOCK) {\n            if (null != testingServer) {\n                log.info(\"Embed zookeeper server already exists 2, on {}\", testingServer.getConnectString());\n                return;\n            }\n            start0();\n            waitTestingServerReady();\n        }\n    }\n    \n    private void start0() {\n        try {\n            testingServer = new TestingServer(port);\n            // CHECKSTYLE:OFF\n        } catch (final Exception ex) {\n            // CHECKSTYLE:ON\n            if (!isIgnoredException(ex)) {\n                throw new RuntimeException(ex);\n            } else {\n                log.warn(\"Start embed zookeeper server got exception: {}\", ex.getMessage());\n            }\n        } finally {\n            Runtime.getRuntime().addShutdownHook(new Thread(() -> {\n                try {\n                    testingServer.close();\n                } catch (final IOException ignored) {\n                }\n                log.info(\"Close embed zookeeper server done\");\n            }));\n        }\n    }\n    \n    private void waitTestingServerReady() {\n        int maxRetries = 60;\n        try (CuratorFramework client = buildCuratorClient()) {\n            client.start();\n            int round = 0;\n            while (round < maxRetries) {\n                try {\n                    if (client.getZookeeperClient().isConnected()) {\n                        log.info(\"client is connected\");\n                        break;\n                    }\n                    if (client.blockUntilConnected(500, TimeUnit.MILLISECONDS)) {\n                        CuratorFrameworkState state = client.getState();\n                        Collection<String> childrenKeys = client.getChildren().forPath(\"/\");\n                        log.info(\"TestingServer connected, state={}, childrenKeys={}\", state, childrenKeys);\n                        break;\n                    }\n                    // CHECKSTYLE:OFF\n                } catch (final Exception ignored) {\n                    // CHECKSTYLE:ON\n                }\n                ++round;\n            }\n        }\n    }\n    \n    private CuratorFramework buildCuratorClient() {\n        CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder();\n        int retryIntervalMilliseconds = 500;\n        int maxRetries = 3;\n        builder.connectString(getConnectionString())\n                .retryPolicy(new ExponentialBackoffRetry(retryIntervalMilliseconds, maxRetries, retryIntervalMilliseconds * maxRetries))\n                .namespace(\"test\");\n        builder.sessionTimeoutMs(60 * 1000);\n        builder.connectionTimeoutMs(500);\n        return builder.build();\n    }\n    \n    private boolean isIgnoredException(final Throwable cause) {\n        return cause instanceof KeeperException.ConnectionLossException || cause instanceof KeeperException.NoNodeException || cause instanceof KeeperException.NodeExistsException;\n    }\n    \n    /**\n     * Get the connection string.\n     *\n     * @return connection string\n     */\n    public String getConnectionString() {\n        return testingServer.getConnectString();\n    }\n}\n"
  },
  {
    "path": "test/util/src/main/java/org/apache/shardingsphere/elasticjob/test/util/ReflectionUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  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.apache.shardingsphere.elasticjob.test.util;\n\nimport lombok.AccessLevel;\nimport lombok.NoArgsConstructor;\nimport lombok.SneakyThrows;\n\nimport java.lang.reflect.Field;\n\n/**\n * Reflection utilities.\n */\n@NoArgsConstructor(access = AccessLevel.PRIVATE)\npublic final class ReflectionUtils {\n    \n    /**\n     * Get field value.\n     *\n     * @param target target object\n     * @param fieldName field name\n     * @return field value\n     */\n    @SneakyThrows(ReflectiveOperationException.class)\n    public static Object getFieldValue(final Object target, final String fieldName) {\n        Field field = target.getClass().getDeclaredField(fieldName);\n        boolean originAccessible = field.isAccessible();\n        if (!originAccessible) {\n            field.setAccessible(true);\n        }\n        Object result = field.get(target);\n        field.setAccessible(originAccessible);\n        return result;\n    }\n    \n    /**\n     * Get static field value.\n     *\n     * @param target target class\n     * @param fieldName field name\n     * @return field value\n     */\n    @SneakyThrows(ReflectiveOperationException.class)\n    public static Object getStaticFieldValue(final Class<?> target, final String fieldName) {\n        Field field = target.getDeclaredField(fieldName);\n        boolean originAccessible = field.isAccessible();\n        if (!originAccessible) {\n            field.setAccessible(true);\n        }\n        Object result = field.get(null);\n        field.setAccessible(originAccessible);\n        return result;\n    }\n    \n    /**\n     * Set field value.\n     *\n     * @param target target object\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    @SneakyThrows(ReflectiveOperationException.class)\n    public static void setFieldValue(final Object target, final String fieldName, final Object fieldValue) {\n        Field field = target.getClass().getDeclaredField(fieldName);\n        boolean originAccessible = field.isAccessible();\n        if (!originAccessible) {\n            field.setAccessible(true);\n        }\n        field.set(target, fieldValue);\n        field.setAccessible(originAccessible);\n    }\n    \n    /**\n     * Set superclass field value.\n     *\n     * @param target target object\n     * @param fieldName field name\n     * @param fieldValue field value\n     */\n    @SneakyThrows(ReflectiveOperationException.class)\n    public static void setSuperclassFieldValue(final Object target, final String fieldName, final Object fieldValue) {\n        Field field = target.getClass().getSuperclass().getDeclaredField(fieldName);\n        boolean originAccessible = field.isAccessible();\n        if (!originAccessible) {\n            field.setAccessible(true);\n        }\n        field.set(target, fieldValue);\n        field.setAccessible(originAccessible);\n    }\n}\n"
  }
]