[
  {
    "path": ".editorconfig",
    "content": "# EditorConfig is awesome: https://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n[*]\nindent_style = tab\nindent_size = 4\nend_of_line = lf\ninsert_final_newline = true\n\n[*.yml]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".github/dco.yml",
    "content": "require:\n  members: false\n"
  },
  {
    "path": ".github/workflows/ci-maven-main.yml",
    "content": "name: CI PRs\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n    branches:\n      - main\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    name: CI PR Build\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-java@v2\n        with:\n          distribution: adopt\n          java-version: 17\n      - run: mvn \"-Dmaven.repo.local=.m2\" -U -B package -s .settings.xml\n"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "content": "name: Spring Cloud Task CI Job\n\non:\n  push:\n    branches:\n      - main\n      - 4.3.x\n\n  # Scheduled builds run daily at midnight UTC\n  schedule:\n    - cron: '0 0 * * *'\n\n  # Manual trigger with optional branch override\n  workflow_dispatch:\n    inputs:\n      branches:\n        description: \"Which branch should be built (can be a comma-separated list of branches)\"\n        required: true\n        default: 'main'\n        type: string\n\njobs:\n  deploy:\n    uses: spring-cloud/spring-cloud-github-actions/.github/workflows/deploy.yml@main\n    with:\n      branches: ${{ inputs.branches }}\n    secrets:\n      ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}\n      ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}\n      COMMERCIAL_ARTIFACTORY_USERNAME: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}\n      COMMERCIAL_ARTIFACTORY_PASSWORD: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}\n      DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}\n      DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/deploy-docs.yml",
    "content": "name: Deploy Docs\non:\n  push:\n    branches-ignore: [ gh-pages ]\n    tags: '**'\n  repository_dispatch:\n    types: request-build-reference # legacy\n  #schedule:\n  #- cron: '0 10 * * *' # Once per day at 10am UTC\n  workflow_dispatch:\npermissions:\n  actions: write\njobs:\n  build:\n    runs-on: ubuntu-latest\n    # if: github.repository_owner == 'spring-cloud'\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v3\n        with:\n          ref: docs-build\n          fetch-depth: 1\n      - name: Dispatch (partial build)\n        if: github.ref_type == 'branch'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD) -f build-refname=${{ github.ref_name }}\n      - name: Dispatch (full build)\n        if: github.ref_type == 'tag'\n        env:\n          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        run: gh workflow run deploy-docs.yml -r $(git rev-parse --abbrev-ref HEAD)\n"
  },
  {
    "path": ".gitignore",
    "content": "*~\n.#*\n*#\n*.sw*\n_site/\n.factorypath\n.gradletasknamecache\n.DS_Store\n/application.yml\n/application.properties\nasciidoctor.css\natlassian-ide-plugin.xml\nbin/\nbuild/\ndump.rdb\nout\nspring-shell.log\ntarget/\ntest-output\nresult.txt\n.flattened-pom.xml\n\n# Eclipse artifacts, including WTP generated manifests\n.classpath\n.project\n.settings/\n.springBeans\nspring-*/src/main/java/META-INF/MANIFEST.MF\n\n# IDEA artifacts and output dirs\n*.iml\n*.ipr\n*.iws\n.idea/*\n\n# Github Actions\n.m2\n\nnode\nnode_modules\nbuild\n/package.json\npackage-lock.json\n"
  },
  {
    "path": ".mvn/jvm.config",
    "content": "-Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom\n"
  },
  {
    "path": ".mvn/maven.config",
    "content": "-DaltSnapshotDeploymentRepository=repo.spring.io::default::https://repo.spring.io/libs-snapshot-local\n-P spring\n"
  },
  {
    "path": ".mvn/wrapper/maven-wrapper.properties",
    "content": "# 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.\ndistributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.1/apache-maven-3.9.1-bin.zip\nwrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar\n"
  },
  {
    "path": ".settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ /*\n  ~  * Copyright 2016-2019 the original author or authors.\n  ~  *\n  ~  * Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  * you may not use this file except in compliance with the License.\n  ~  * You may obtain a copy of the License at\n  ~  *\n  ~  *      https://www.apache.org/licenses/LICENSE-2.0\n  ~  *\n  ~  * Unless required by applicable law or agreed to in writing, software\n  ~  * distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  * See the License for the specific language governing permissions and\n  ~  * limitations under the License.\n  ~  */\n  -->\n\n<settings>\n\t<servers>\n\t\t<server>\n\t\t\t<id>repo.spring.io</id>\n\t\t\t<username>${env.CI_DEPLOY_USERNAME}</username>\n\t\t\t<password>${env.CI_DEPLOY_PASSWORD}</password>\n\t\t</server>\n\t</servers>\n\t<profiles>\n\t\t<profile>\n\t\t\t<!--\n\t\t\t\tN.B. this profile is only here to support users and IDEs that do not use Maven 3.3.\n\t\t\t\tIt isn't needed on the command line if you use the wrapper script (mvnw) or if you use\n\t\t\t\ta native Maven with the right version. Eclipse users should points their Maven tooling to\n\t\t\t\tthis settings file, or copy the profile into their ~/.m2/settings.xml.\n\t\t\t-->\n\t\t\t<id>spring</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t</activation>\n\t\t\t<repositories>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>spring-snapshots</id>\n\t\t\t\t\t<name>Spring Snapshots</name>\n\t\t\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>spring-milestones</id>\n\t\t\t\t\t<name>Spring Milestones</name>\n\t\t\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>spring-releases</id>\n\t\t\t\t\t<name>Spring Releases</name>\n\t\t\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t</repositories>\n\t\t\t<pluginRepositories>\n\t\t\t\t<pluginRepository>\n\t\t\t\t\t<id>spring-snapshots</id>\n\t\t\t\t\t<name>Spring Snapshots</name>\n\t\t\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</pluginRepository>\n\t\t\t\t<pluginRepository>\n\t\t\t\t\t<id>spring-milestones</id>\n\t\t\t\t\t<name>Spring Milestones</name>\n\t\t\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</pluginRepository>\n\t\t\t</pluginRepositories>\n\t\t</profile>\n\t</profiles>\n\t<pluginGroups>\n\t\t<pluginGroup>io.spring.javaformat</pluginGroup>\n\t</pluginGroups>\n</settings>\n"
  },
  {
    "path": ".springformat",
    "content": ""
  },
  {
    "path": "CONTRIBUTING.adoc",
    "content": "= Contributing to Spring Cloud Task\n\n:github: https://github.com/spring-cloud/spring-cloud-task\n\nSpring Cloud Task is released under the Apache 2.0 license. If you would like to contribute something, or want to hack on the code this document should help you get started.\n\n\n== Using GitHub Issues\nWe use GitHub issues to track bugs and enhancements.\nIf you have a general usage question please ask on https://stackoverflow.com[Stack Overflow].\nThe Spring Cloud Task team and the broader community monitor the https://stackoverflow.com/tags/spring-cloud-Task[`spring-cloud-task`] tag.\n\nIf you are reporting a bug, please help to speed up problem diagnosis by providing as much information as possible.\nIdeally, that would include a small sample project that reproduces the problem.\n\n\n\n== Reporting Security Vulnerabilities\nIf you think you have found a security vulnerability in Spring Cloud Task please *DO NOT* disclose it publicly until we've had a chance to fix it.\nPlease don't report security vulnerabilities using GitHub issues, instead head over to https://spring.io/security-policy and learn how to disclose them responsibly.\n\n\n\n== Developer Certificate of Origin\nAll commits must include a **Signed-off-by** trailer at the end of each commit message to indicate that the contributor agrees to the Developer Certificate of Origin.\nFor additional details, please refer to the blog post https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring[Hello DCO, Goodbye CLA: Simplifying Contributions to Spring].\n\n\n=== Code Conventions and Housekeeping\n\nNone of the following guidelines is essential for a pull request, but they all help your fellow developers understand and work with your code.\nThey can also be added after the original pull request but before a merge.\n\n* Use the Spring Framework code format conventions. If you use Eclipse, you can import formatter settings by using the `eclipse-code-formatter.xml` file from the https://github.com/spring-cloud/spring-cloud-build/blob/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml[Spring Cloud Build] project.\nIf you use IntelliJ, you can use the https://plugins.jetbrains.com/plugin/6546[Eclipse Code Formatter Plugin] to import the same file.\n* Make sure all new `.java` files have a simple Javadoc class comment with at least an  `@author` tag identifying you, and preferably at least a paragraph describing the class's purpose.\n* Add the ASF license header comment to all new `.java` files (to do so, copy it from existing files in the project).\n* Add yourself as an `@author` to the .java files that you modify substantially (more than cosmetic changes).\n* Add some Javadocs and, if you change the namespace, some XSD doc elements.\n* A few unit tests would help a lot as well. Someone has to do it, and your fellow developers appreciate the effort.\n* If no one else uses your branch, rebase it against the current master (or other target branch in the main project).\n* When writing a commit message, follow https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[these conventions].\nIf you fix an existing issue, add `Fixes gh-XXXX` (where XXXX is the issue number) at the end of the commit message.\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        https://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       https://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "README.adoc",
    "content": "////\nDO NOT EDIT THIS FILE. IT WAS GENERATED.\nManual changes to this file will be lost when it is generated again.\nEdit the files in the src/main/asciidoc/ directory instead.\n////\n\n\n[[spring-cloud-task]]\n= Spring Cloud Task\n\nIs a project centered around the idea of processing on demand.  A user is able to develop\na “task” that can be deployed, executed and removed on demand, yet the result of the\nprocess persists beyond the life of the task for future reporting.\n\n\n[[requirements:]]\n== Requirements:\n\n* Java 17 or Above\n\n[[build-main-project:]]\n== Build Main Project:\n\n[source,shell,indent=2]\n----\n$ ./mvnw clean install\n----\n\n[[example:]]\n== Example:\n\n[source,java,indent=2]\n----\n@SpringBootApplication\n@EnableTask\npublic class MyApp {\n\n    @Bean\n    public MyTaskApplication myTask() {\n        return new MyTaskApplication();\n    }\n\n    public static void main(String[] args) {\n        SpringApplication.run(MyApp.class);\n    }\n\n    public static class MyTaskApplication implements ApplicationRunner {\n\n        @Override\n        public void run(ApplicationArguments args) throws Exception {\n            System.out.println(\"Hello World\");\n        }\n    }\n}\n----\n\n[[code-of-conduct]]\n== Code of Conduct\nThis project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.adoc[code of conduct]. By participating, you  are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.\n\n[[building-the-project]]\n== Building the Project\n\nThis project requires that you invoke the Javadoc engine from the Maven command line. You can do so by appending `javadoc:aggregate` to the rest of your Maven command.\nFor example, to build the entire project, you could use `mvn clean install -DskipTests -P docs`.\n"
  },
  {
    "path": "docs/antora-playbook.yml",
    "content": "antora:\n  extensions:\n    - require: '@springio/antora-extensions'\n      root_component_name: 'cloud-task'\nsite:\n  title: Spring Cloud Task\n  url: https://docs.spring.io/spring-cloud-task/reference/\ncontent:\n  sources:\n    - url: ./..\n      branches: HEAD\n      start_path: docs\n      worktrees: true\nasciidoc:\n  attributes:\n    page-stackoverflow-url: https://stackoverflow.com/tags/spring-cloud-task\n    page-pagination: ''\n    hide-uri-scheme: '@'\n    tabs-sync-option: '@'\n    chomp: 'all'\n  extensions:\n    - '@asciidoctor/tabs'\n    - '@springio/asciidoctor-extensions'\n  sourcemap: true\nurls:\n  latest_version_segment: ''\nruntime:\n  log:\n    failure_level: warn\n    format: pretty\nui:\n  bundle:\n    url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.15/ui-bundle.zip\n"
  },
  {
    "path": "docs/antora.yml",
    "content": "name: cloud-task\nversion: true\ntitle: spring-cloud-task\nnav:\n  - modules/ROOT/nav.adoc\next:\n  collector:\n    run:\n      command: ./mvnw --no-transfer-progress -B process-resources -Pdocs -pl docs -Dantora-maven-plugin.phase=none -Dgenerate-docs.phase=none -Dgenerate-readme.phase=none -Dgenerate-cloud-resources.phase=none -Dmaven-dependency-plugin-for-docs.phase=none -Dmaven-dependency-plugin-for-docs-classes.phase=none -DskipTests -DdisableConfigurationProperties\n      local: true\n    scan:\n      dir: ./target/classes/antora-resources/\n"
  },
  {
    "path": "docs/modules/ROOT/nav.adoc",
    "content": "* xref:index.adoc[Introduction]\n* xref:getting-started.adoc[]\n* xref:features.adoc[]\n* xref:batch.adoc[]\n* xref:batch-starter.adoc[]\n* xref:stream.adoc[]\n* xref:appendix.adoc[]\n** xref:appendix-task-repository-schema.adoc[]\n** xref:appendix-building-the-documentation.adoc[]\n** xref:observability.adoc[]\n"
  },
  {
    "path": "docs/modules/ROOT/pages/_attributes.adoc",
    "content": ":doctype: book\n:idprefix:\n:idseparator: -\n:tabsize: 4\n:numbered:\n:sectanchors:\n:sectnums:\n:icons: font\n:hide-uri-scheme:\n:docinfo: shared,private\n\n:sc-ext: java\n:project-full-name: Spring Cloud Task\n\n// project-specific attributes\n:spring-cloud-task-repo: snapshot\n:github-tag: master\n:spring-cloud-task-docs-version: current\n:spring-cloud-task-docs: https://docs.spring.io/spring-cloud-task/docs/{spring-cloud-task-docs-version}/reference\n:spring-cloud-task-docs-current: https://docs.spring.io/spring-cloud-task/reference/\n:github-repo: spring-cloud/spring-cloud-task\n:github-raw: https://raw.github.com/{github-repo}/{github-tag}\n:github-code: https://github.com/{github-repo}/tree/{github-tag}\n:github-wiki: https://github.com/{github-repo}/wiki\n:github-master-code: https://github.com/{github-repo}/tree/master\n:sc-ext: java\n:sc-spring-boot: {github-code}/spring-boot/src/main/java/org/springframework/boot\n:dc-ext: html\n:dc-root: https://docs.spring.io/spring-cloud-task/docs/{spring-cloud-dataflow-docs-version}/api\n:dc-spring-boot: {dc-root}/org/springframework/boot\n:dependency-management-plugin: https://github.com/spring-gradle-plugins/dependency-management-plugin\n:dependency-management-plugin-documentation: {dependency-management-plugin}/blob/master/README.md\n:spring-boot-maven-plugin-site: https://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/maven-plugin\n:spring-reference: https://docs.spring.io/spring/docs/{spring-docs-version}/spring-framework-reference/htmlsingle\n:spring-security-reference: https://docs.spring.io/spring-security/site/docs/{spring-security-docs-version}/reference/htmlsingle\n:spring-javadoc: https://docs.spring.io/spring/docs/{spring-docs-version}/javadoc-api/org/springframework\n:spring-amqp-javadoc: https://docs.spring.io/spring-amqp/docs/current/api/org/springframework/amqp\n:spring-data-javadoc: https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa\n:spring-data-commons-javadoc: https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data\n:spring-data-mongo-javadoc: https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb\n:spring-data-rest-javadoc: https://docs.spring.io/spring-data/rest/docs/current/api/org/springframework/data/rest\n:gradle-userguide: https://www.gradle.org/docs/current/userguide\n:propdeps-plugin: https://github.com/spring-projects/gradle-plugins/tree/master/propdeps-plugin\n:ant-manual: https://ant.apache.org/manual\n:attributes: allow-uri-read\n"
  },
  {
    "path": "docs/modules/ROOT/pages/appendix-building-the-documentation.adoc",
    "content": "\n[[appendix-building-the-documentation]]\n= Building This Documentation\n:page-section-summary-toc: 1\n\nThis project uses Maven to generate this documentation. To generate it for yourself,\nrun the following command: `$ mvn clean install -DskipTests -P docs`.\n"
  },
  {
    "path": "docs/modules/ROOT/pages/appendix-task-repository-schema.adoc",
    "content": "[[appendix-task-repository-schema]]\n= Task Repository Schema\n\n[[partintro]]\n--\nThis appendix provides an ERD for the database schema used in the task repository.\n--\n\nimage::task_schema.png[]\n\n[[table-information]]\n== Table Information\n--\n\n.TASK_EXECUTION\nStores the task execution information.\n[width=\"80%\", cols=\"1,1,1,1,10\", options=\"header\"]\n|=========================================================\n|Column Name |Required |Type |Field Length |Notes\n\n|TASK_EXECUTION_ID |TRUE |BIGINT | X |\nSpring Cloud Task Framework at app startup establishes the next available id as obtained from the `TASK_SEQ`. Or if the record is created outside of task then the value must be populated at record creation time.\n\n|START_TIME |FALSE | DATETIME(6) | X | Spring Cloud Task Framework at app startup establishes the value.\n\n|END_TIME |FALSE | DATETIME(6) | X | Spring Cloud Task Framework at app exit establishes the value.\n\n|TASK_NAME |FALSE | VARCHAR | 100 | Spring Cloud Task Framework at app startup will set this to \"Application\" unless user establish the name using the `spring.application.name`.\n\n|EXIT_CODE |FALSE | INTEGER | X | Follows Spring Boot defaults unless overridden by the user as discussed https://docs.spring.io/spring-cloud-task/docs/current/reference/#features-lifecycle-exit-codes[here].\n\n|EXIT_MESSAGE |FALSE | VARCHAR | 2500 | User Defined as discussed https://docs.spring.io/spring-cloud-task/docs/current/reference/#features-task-execution-listener-exit-messages[here].\n\n|ERROR_MESSAGE |FALSE | VARCHAR | 2500 | Spring Cloud Task Framework at app exit establishes the value.\n\n|LAST_UPDATED |TRUE | TIMESTAMP | X | Spring Cloud Task Framework at app startup establishes the value. Or if the record is created outside of task then the value must be populated at record creation time.\n\n|EXTERNAL_EXECUTION_ID |FALSE | VARCHAR | 250 | If the `spring.cloud.task.external-execution-id` property is set then Spring Cloud Task Framework at app startup will set this to the value specified.   More information can be found xref:features.adoc#features-external_task_id[here]\n\n|PARENT_TASK_EXECUTION_ID |FALSE |BIGINT | X | If the `spring.cloud.task.parent-execution-id` property is set then Spring Cloud Task Framework at app startup will set this to the value specified.   More information can be found xref:features.adoc#features-parent_task_id[here]\n\n|=========================================================\n\n.TASK_EXECUTION_PARAMS\nStores the parameters used for a task execution\n[width=\"80%\", cols=\"1,1,1,1\", options=\"header\"]\n|=========================================================\n|Column Name |Required |Type |Field Length\n|TASK_EXECUTION_ID |TRUE |BIGINT | X \n\n|TASK_PARAM |FALSE | VARCHAR | 2500 \n\n|=========================================================\n\n.TASK_TASK_BATCH\nUsed to link the task execution to the batch execution.\n[width=\"80%\", cols=\"1,1,1,1\", options=\"header\"]\n|=========================================================\n|Column Name |Required |Type |Field Length\n\n|TASK_EXECUTION_ID |TRUE |BIGINT | X \n\n|JOB_EXECUTION_ID |TRUE | BIGINT | X \n\n|=========================================================\n\n\n.TASK_LOCK\nUsed for the `single-instance-enabled` feature discussed xref:features.adoc#features-single-instance-enabled[here].\n[width=\"80%\", cols=\"1,1,1,1,10\", options=\"header\"]\n|=========================================================\n|Column Name |Required |Type | Field Length |Notes\n\n|LOCK_KEY |TRUE |CHAR | 36 | UUID for the this lock\n\n|REGION |TRUE | VARCHAR  | 100 | User can establish a group of locks using this field.\n\n|CLIENT_ID |TRUE | CHAR  | 36 | The task execution id that contains the name of the app to lock.\n\n|CREATED_DATE |TRUE | DATETIME  | X | The date that the entry was created\n\n|=========================================================\n\n\nNOTE: The DDL for setting up tables for each database type can be found https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task[here].\n--\n\n[[sql-server]]\n== SQL Server\nBy default Spring Cloud Task uses a sequence table for determining the `TASK_EXECUTION_ID` for the `TASK_EXECUTION` table.\nHowever, when launching multiple tasks simultaneously while using SQL Server, this can cause a deadlock to occur on the `TASK_SEQ` table.\nThe resolution is to drop the `TASK_EXECUTION_SEQ` table and create a sequence using the same name.   For example:\n```\nDROP TABLE TASK_SEQ;\n\nCREATE SEQUENCE [DBO].[TASK_SEQ] AS BIGINT\n START WITH 1\n INCREMENT BY 1;\n```\nNOTE: Set the `START WITH`  to a higher value than your current execution id.\n"
  },
  {
    "path": "docs/modules/ROOT/pages/appendix.adoc",
    "content": "\n[[appendix]]\n= Appendices\n:page-section-summary-toc: 1\n\n\n\nifndef::train-docs[]\nendif::[]\n\n"
  },
  {
    "path": "docs/modules/ROOT/pages/batch-starter.adoc",
    "content": "\n[[batch-job-starter]]\n= Single Step Batch Job Starter\n\n[[partintro]]\n--\nThis section goes into how to develop a Spring Batch `Job` with a single `Step` by using the\nstarter included in Spring Cloud Task. This starter lets you use configuration\nto define an `ItemReader`, an `ItemWriter`, or a full single-step Spring Batch `Job`.\nFor more about Spring Batch and its capabilities, see the\nhttps://spring.io/projects/spring-batch[Spring Batch documentation].\n--\n\nTo obtain the starter for Maven, add the following to your build:\n\n[source,xml]\n----\n<dependency>\n    <groupId>org.springframework.cloud</groupId>\n    <artifactId>spring-cloud-starter-single-step-batch-job</artifactId>\n    <version>2.3.0</version>\n</dependency>\n----\n\nTo obtain the starter for Gradle, add the following to your build:\n\n[source,groovy]\n----\ncompile \"org.springframework.cloud:spring-cloud-starter-single-step-batch-job:2.3.0\"\n----\n\n[[job-definition]]\n== Defining a Job\n\nYou can use the starter to define as little as an `ItemReader` or an `ItemWriter` or as much as a full `Job`.\nIn this section, we define which properties are required to be defined to configure a\n`Job`.\n\n[[job-definition-properties]]\n=== Properties\n\nTo begin, the starter provides a set of properties that let you configure the basics of a Job with one Step:\n\n.Job Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.jobName`\n| `String`\n| `null`\n| The name of the job.\n\n| `spring.batch.job.stepName`\n| `String`\n| `null`\n| The name of the step.\n\n| `spring.batch.job.chunkSize`\n| `Integer`\n| `null`\n| The number of items to be processed per transaction.\n|===\n\nWith the above properties configured, you have a job with a single, chunk-based step.\nThis chunk-based step reads, processes, and writes `Map<String, Object>` instances as the\nitems. However, the step does not yet do anything. You need to configure an `ItemReader`, an\noptional `ItemProcessor`, and an `ItemWriter` to give it something to do. To configure one\nof these, you can either use properties and configure one of the options that has provided\nautoconfiguration or you can configure your own with the standard Spring configuration\nmechanisms.\n\nNOTE: If you configure your own, the input and output types must match the others in the step.\nThe `ItemReader` implementations and `ItemWriter` implementations in this starter all use\na `Map<String, Object>` as the input and the output item.\n\n[[item-readers]]\n== Autoconfiguration for ItemReader Implementations\n\nThis starter provides autoconfiguration for four different `ItemReader` implementations:\n`AmqpItemReader`, `FlatFileItemReader`, `JdbcCursorItemReader`, and `KafkaItemReader`.\nIn this section, we outline how to configure each of these by using the provided\nautoconfiguration.\n\n[[amqpitemreader]]\n=== AmqpItemReader\n\nYou can read from a queue or topic with AMQP by using the `AmqpItemReader`. The\nautoconfiguration for this `ItemReader` implementation is dependent upon two sets of\nconfiguration. The first is the configuration of an `AmqpTemplate`. You can either\nconfigure this yourself or use the autoconfiguration provided by Spring Boot. See the\nhttps://docs.spring.io/spring-boot/docs/3.0.x/reference/htmlsingle/#messaging.amqp.rabbitmq[Spring Boot AMQP documentation].\nOnce you have configured the `AmqpTemplate`, you can enable the batch capabilities to support it\nby setting the following properties:\n\n.`AmqpItemReader` Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.amqpitemreader.enabled`\n| `boolean`\n| `false`\n| If `true`, the autoconfiguration will execute.\n\n| `spring.batch.job.amqpitemreader.jsonConverterEnabled`\n| `boolean`\n| `true`\n| Indicates if the `Jackson2JsonMessageConverter` should be registered to parse messages.\n|===\n\nFor more information, see the https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/amqp/AmqpItemReader.html[`AmqpItemReader` documentation].\n\n[[flatfileitemreader]]\n=== FlatFileItemReader\n\n`FlatFileItemReader` lets you read from flat files (such as CSVs\nand other file formats). To read from a file, you can provide some components\nyourself through normal Spring configuration (`LineTokenizer`, `RecordSeparatorPolicy`,\n`FieldSetMapper`, `LineMapper`, or `SkippedLinesCallback`). You can also use the\nfollowing properties to configure the reader:\n\n.`FlatFileItemReader` Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.flatfileitemreader.saveState`\n| `boolean`\n| `true`\n| Determines if the state should be saved for restarts.\n\n| `spring.batch.job.flatfileitemreader.name`\n| `String`\n| `null`\n| Name used to provide unique keys in the `ExecutionContext`.\n\n| `spring.batch.job.flatfileitemreader.maxItemcount`\n| `int`\n| `Integer.MAX_VALUE`\n| Maximum number of items to be read from the file.\n\n| `spring.batch.job.flatfileitemreader.currentItemCount`\n| `int`\n| 0\n| Number of items that have already been read. Used on restarts.\n\n| `spring.batch.job.flatfileitemreader.comments`\n| `List<String>`\n| empty List\n| A list of Strings that indicate commented lines (lines to be ignored) in the file.\n\n| `spring.batch.job.flatfileitemreader.resource`\n| `Resource`\n| `null`\n| The resource to be read.\n\n| `spring.batch.job.flatfileitemreader.strict`\n| `boolean`\n| `true`\n| If set to `true`, the reader throws an exception if the resource is not found.\n\n| `spring.batch.job.flatfileitemreader.encoding`\n| `String`\n| `FlatFileItemReader.DEFAULT_CHARSET`\n| Encoding to be used when reading the file.\n\n| `spring.batch.job.flatfileitemreader.linesToSkip`\n| `int`\n| 0\n| Indicates the number of lines to skip at the start of a file.\n\n| `spring.batch.job.flatfileitemreader.delimited`\n| `boolean`\n| `false`\n| Indicates whether the file is a delimited file (CSV and other formats). Only one of this property or `spring.batch.job.flatfileitemreader.fixedLength` can be `true` at the same time.\n\n| `spring.batch.job.flatfileitemreader.delimiter`\n| `String`\n| `DelimitedLineTokenizer.DELIMITER_COMMA`\n| If reading a delimited file, indicates the delimiter to parse on.\n\n| `spring.batch.job.flatfileitemreader.quoteCharacter`\n| `char`\n| `DelimitedLineTokenizer.DEFAULT_QUOTE_CHARACTER`\n| Used to determine the character used to quote values.\n\n| `spring.batch.job.flatfileitemreader.includedFields`\n| `List<Integer>`\n| empty list\n| A list of indices to determine which fields in a record to include in the item.\n\n| `spring.batch.job.flatfileitemreader.fixedLength`\n| `boolean`\n| `false`\n| Indicates if a file's records are parsed by column numbers. Only one of this property or `spring.batch.job.flatfileitemreader.delimited` can be `true` at the same time.\n\n| `spring.batch.job.flatfileitemreader.ranges`\n| `List<Range>`\n| empty list\n| List of column ranges by which to parse a fixed width record. See the https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/file/transform/Range.html[Range documentation].\n\n| `spring.batch.job.flatfileitemreader.names`\n| `String []`\n| `null`\n| List of names for each field parsed from a record. These names are the keys in the `Map<String, Object>` in the items returned from this `ItemReader`.\n\n| `spring.batch.job.flatfileitemreader.parsingStrict`\n| `boolean`\n| `true`\n| If set to `true`, the mapping fails if the fields cannot be mapped.\n|===\n\nSee the https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/file/FlatFileItemReader.html[`FlatFileItemReader` documentation].\n\n[[jdbcCursorItemReader]]\n=== JdbcCursorItemReader\n\nThe `JdbcCursorItemReader` runs a query against a relational database and iterates over\nthe resulting cursor (`ResultSet`) to provide the resulting items. This autoconfiguration\nlets you provide a `PreparedStatementSetter`, a `RowMapper`, or both. You\ncan also use the following properties to configure a `JdbcCursorItemReader`:\n\n.`JdbcCursorItemReader` Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.jdbccursoritemreader.saveState`\n| `boolean`\n| `true`\n| Determines whether the state should be saved for restarts.\n\n| `spring.batch.job.jdbccursoritemreader.name`\n| `String`\n| `null`\n| Name used to provide unique keys in the `ExecutionContext`.\n\n| `spring.batch.job.jdbccursoritemreader.maxItemcount`\n| `int`\n| `Integer.MAX_VALUE`\n| Maximum number of items to be read from the file.\n\n| `spring.batch.job.jdbccursoritemreader.currentItemCount`\n| `int`\n| 0\n| Number of items that have already been read. Used on restarts.\n\n| `spring.batch.job.jdbccursoritemreader.fetchSize`\n| `int`\n|\n| A hint to the driver to indicate how many records to retrieve per call to the database system. For best performance, you usually want to set it to match the chunk size.\n\n| `spring.batch.job.jdbccursoritemreader.maxRows`\n| `int`\n|\n| Maximum number of items to read from the database.\n\n| `spring.batch.job.jdbccursoritemreader.queryTimeout`\n| `int`\n|\n| Number of milliseconds for the query to timeout.\n\n| `spring.batch.job.jdbccursoritemreader.ignoreWarnings`\n| `boolean`\n| `true`\n| Determines whether the reader should ignore SQL warnings when processing.\n\n| `spring.batch.job.jdbccursoritemreader.verifyCursorPosition`\n| `boolean`\n| `true`\n| Indicates whether the cursor's position should be verified after each read to verify that the `RowMapper` did not advance the cursor.\n\n| `spring.batch.job.jdbccursoritemreader.driverSupportsAbsolute`\n| `boolean`\n| `false`\n| Indicates whether the driver supports absolute positioning of a cursor.\n\n| `spring.batch.job.jdbccursoritemreader.useSharedExtendedConnection`\n| `boolean`\n| `false`\n| Indicates whether the connection is shared with other processing (and is therefore part of a transaction).\n\n| `spring.batch.job.jdbccursoritemreader.sql`\n| `String`\n| `null`\n| SQL query from which to read.\n|===\n\nYou can also specify JDBC DataSource specifically for the reader by using the following properties:\n.`JdbcCursorItemReader` Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.jdbccursoritemreader.datasource.enable`\n| `boolean`\n| `false`\n| Determines whether `JdbcCursorItemReader` `DataSource` should be enabled.\n\n| `jdbccursoritemreader.datasource.url`\n| `String`\n| `null`\n| JDBC URL of the database.\n\n| `jdbccursoritemreader.datasource.username`\n| `String`\n| `null`\n| Login username of the database.\n\n| `jdbccursoritemreader.datasource.password`\n| `String`\n| `null`\n| Login password of the database.\n\n| `jdbccursoritemreader.datasource.driver-class-name`\n| `String`\n| `null`\n| Fully qualified name of the JDBC driver.\n|===\n\nNOTE: The default `DataSource` will be used by the `JDBCCursorItemReader` if the `jdbccursoritemreader_datasource` is not specified.\n\nSee the https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/database/JdbcCursorItemReader.html[`JdbcCursorItemReader` documentation].\n\n[[kafkaItemReader]]\n=== KafkaItemReader\n\nIngesting a partition of data from a Kafka topic is useful and exactly what the\n`KafkaItemReader` can do. To configure a `KafkaItemReader`, two pieces\nof configuration are required. First, configuring Kafka with Spring Boot's Kafka\nautoconfiguration is required (see the\nhttps://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#messaging.kafka.additional-properties[Spring Boot Kafka documentation]).\nOnce you have configured the Kafka properties from Spring Boot, you can configure the `KafkaItemReader`\nitself by setting the following properties:\n\n.`KafkaItemReader` Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.kafkaitemreader.name`\n| `String`\n| `null`\n| Name used to provide unique keys in the `ExecutionContext`.\n\n| `spring.batch.job.kafkaitemreader.topic`\n| `String`\n| `null`\n| Name of the topic from which to read.\n\n| `spring.batch.job.kafkaitemreader.partitions`\n| `List<Integer>`\n| empty list\n| List of partition indices from which to read.\n\n| `spring.batch.job.kafkaitemreader.pollTimeOutInSeconds`\n| `long`\n| 30\n| Timeout for the `poll()` operations.\n\n| `spring.batch.job.kafkaitemreader.saveState`\n| `boolean`\n| `true`\n| Determines whether the state should be saved for restarts.\n|===\n\nSee the https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/kafka/KafkaItemReader.html[`KafkaItemReader` documentation].\n\n[[nativeCompilation]]\n=== Native Compilation\nThe advantage of Single Step Batch Processing is that it lets you dynamically select which reader and writer beans to use at runtime when you use the JVM.\nHowever, when you use native compilation, you must determine the reader and writer at build time instead of runtime.\nThe following example does so:\n\n[source,xml]\n<plugin>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-maven-plugin</artifactId>\n    <executions>\n        <execution>\n            <id>process-aot</id>\n            <goals>\n                <goal>process-aot</goal>\n            </goals>\n            <configuration>\n                <jvmArguments>\n                    -Dspring.batch.job.flatfileitemreader.name=fooReader\n                    -Dspring.batch.job.flatfileitemwriter.name=fooWriter\n                </jvmArguments>\n            </configuration>\n        </execution>\n    </executions>\n</plugin>\n\n[[item-processors]]\n== ItemProcessor Configuration\n\nThe single-step batch job autoconfiguration accepts an `ItemProcessor` if one\nis available within the `ApplicationContext`. If one is found of the correct type\n(`ItemProcessor<Map<String, Object>, Map<String, Object>>`), it is autowired\ninto the step.\n\n[[item-writers]]\n== Autoconfiguration for ItemWriter implementations\n\nThis starter provides autoconfiguration for `ItemWriter` implementations that\nmatch the supported `ItemReader` implementations: `AmqpItemWriter`,\n`FlatFileItemWriter`, `JdbcItemWriter`, and `KafkaItemWriter`. This section\ncovers how to use autoconfiguration to configure a supported `ItemWriter`.\n\n[[amqpitemwriter]]\n=== AmqpItemWriter\n\nTo write to a RabbitMQ queue, you need two sets of configuration. First, you need an\n`AmqpTemplate`. The easiest way to get this is by using Spring Boot's\nRabbitMQ autoconfiguration. See the https://docs.spring.io/spring-boot/docs/3.0.x/reference/htmlsingle/#messaging.amqp.rabbitmq[Spring Boot AMQP documentation].\n\nOnce you have configured the `AmqpTemplate`, you can configure the `AmqpItemWriter` by setting the\nfollowing properties:\n\n.`AmqpItemWriter` Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.amqpitemwriter.enabled`\n| `boolean`\n| `false`\n| If `true`, the autoconfiguration runs.\n\n| `spring.batch.job.amqpitemwriter.jsonConverterEnabled`\n| `boolean`\n| `true`\n| Indicates whether `Jackson2JsonMessageConverter` should be registered to convert messages.\n|===\n\n[[flatfileitemwriter]]\n=== FlatFileItemWriter\n\nTo write a file as the output of the step, you can configure `FlatFileItemWriter`.\nAutoconfiguration accepts components that have been explicitly configured (such as `LineAggregator`,\n`FieldExtractor`, `FlatFileHeaderCallback`, or a `FlatFileFooterCallback`) and\ncomponents that have been configured by setting the following properties specified:\n\n.`FlatFileItemWriter` Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.flatfileitemwriter.resource`\n| `Resource`\n| `null`\n| The resource to be read.\n\n| `spring.batch.job.flatfileitemwriter.delimited`\n| `boolean`\n| `false`\n| Indicates whether the output file is a delimited file. If `true`, `spring.batch.job.flatfileitemwriter.formatted` must be `false`.\n\n| `spring.batch.job.flatfileitemwriter.formatted`\n| `boolean`\n| `false`\n| Indicates whether the output file a formatted file. If `true`, `spring.batch.job.flatfileitemwriter.delimited` must be `false`.\n\n| `spring.batch.job.flatfileitemwriter.format`\n| `String`\n| `null`\n| The format used to generate the output for a formatted file. The formatting is performed by using `String.format`.\n\n| `spring.batch.job.flatfileitemwriter.locale`\n| `Locale`\n| `Locale.getDefault()`\n| The `Locale` to be used when generating the file.\n\n| `spring.batch.job.flatfileitemwriter.maximumLength`\n| `int`\n| 0\n| Max length of the record. If 0, the size is unbounded.\n\n| `spring.batch.job.flatfileitemwriter.minimumLength`\n| `int`\n| 0\n| The minimum record length.\n\n| `spring.batch.job.flatfileitemwriter.delimiter`\n| `String`\n| `,`\n| The `String` used to delimit fields in a delimited file.\n\n| `spring.batch.job.flatfileitemwriter.encoding`\n| `String`\n| `FlatFileItemReader.DEFAULT_CHARSET`\n| Encoding to use when writing the file.\n\n| `spring.batch.job.flatfileitemwriter.forceSync`\n| `boolean`\n| `false`\n| Indicates whether a file should be force-synced to the disk on flush.\n\n| `spring.batch.job.flatfileitemwriter.names`\n| `String []`\n| `null`\n| List of names for each field parsed from a record. These names are the keys in the `Map<String, Object>` for the items received by this `ItemWriter`.\n\n| `spring.batch.job.flatfileitemwriter.append`\n| `boolean`\n| `false`\n| Indicates whether a file should be appended to if the output file is found.\n\n| `spring.batch.job.flatfileitemwriter.lineSeparator`\n| `String`\n| `FlatFileItemWriter.DEFAULT_LINE_SEPARATOR`\n| What `String` to use to separate lines in the output file.\n\n| `spring.batch.job.flatfileitemwriter.name`\n| `String`\n| `null`\n| Name used to provide unique keys in the `ExecutionContext`.\n\n| `spring.batch.job.flatfileitemwriter.saveState`\n| `boolean`\n| `true`\n| Determines whether the state should be saved for restarts.\n\n| `spring.batch.job.flatfileitemwriter.shouldDeleteIfEmpty`\n| `boolean`\n| `false`\n| If set to `true`, an empty file (there is no output) is deleted when the job completes.\n\n| `spring.batch.job.flatfileitemwriter.shouldDeleteIfExists`\n| `boolean`\n| `true`\n| If set to `true` and a file is found where the output file should be, it is deleted before the step begins.\n\n| `spring.batch.job.flatfileitemwriter.transactional`\n| `boolean`\n| `FlatFileItemWriter.DEFAULT_TRANSACTIONAL`\n| Indicates whether the reader is a transactional queue (indicating that the items read are returned to the queue upon a failure).\n|===\n\nSee the https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/file/FlatFileItemWriter.html[`FlatFileItemWriter` documentation].\n\n[[jdbcitemwriter]]\n=== JdbcBatchItemWriter\n\nTo write the output of a step to a relational database, this starter provides the ability\nto autoconfigure a `JdbcBatchItemWriter`. The autoconfiguration lets you provide your\nown `ItemPreparedStatementSetter` or `ItemSqlParameterSourceProvider` and\nconfiguration options by setting the following properties:\n\n.`JdbcBatchItemWriter` Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.jdbcbatchitemwriter.name`\n| `String`\n| `null`\n| Name used to provide unique keys in the `ExecutionContext`.\n\n| `spring.batch.job.jdbcbatchitemwriter.sql`\n| `String`\n| `null`\n| The SQL used to insert each item.\n\n| `spring.batch.job.jdbcbatchitemwriter.assertUpdates`\n| `boolean`\n| `true`\n| Whether to verify that every insert results in the update of at least one record.\n|===\n\nYou can also specify JDBC DataSource specifically for the writer by using the following properties:\n.`JdbcBatchItemWriter` Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.jdbcbatchitemwriter.datasource.enable`\n| `boolean`\n| `false`\n| Determines whether `JdbcCursorItemReader` `DataSource` should be enabled.\n\n| `jdbcbatchitemwriter.datasource.url`\n| `String`\n| `null`\n| JDBC URL of the database.\n\n| `jdbcbatchitemwriter.datasource.username`\n| `String`\n| `null`\n| Login username of the database.\n\n| `jdbcbatchitemwriter.datasource.password`\n| `String`\n| `null`\n| Login password of the database.\n\n| `jdbcbatchitemreader.datasource.driver-class-name`\n| `String`\n| `null`\n| Fully qualified name of the JDBC driver.\n|===\n\nNOTE: The default `DataSource` will be used by the `JdbcBatchItemWriter` if the `jdbcbatchitemwriter_datasource` is not specified.\n\nSee the https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/database/JdbcBatchItemWriter.html[`JdbcBatchItemWriter` documentation].\n\n[[kafkaitemwriter]]\n=== KafkaItemWriter\n\nTo write step output to a Kafka topic, you need `KafkaItemWriter`. This starter\nprovides autoconfiguration for a `KafkaItemWriter` by using facilities from two places.\nThe first is Spring Boot's Kafka autoconfiguration. (See the https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#messaging.kafka.additional-properties[Spring Boot Kafka documentation].)\nSecond, this starter lets you configure two properties on the writer.\n\n.`KafkaItemWriter` Properties\n|===\n| Property | Type | Default Value | Description\n\n| `spring.batch.job.kafkaitemwriter.topic`\n| `String`\n| `null`\n| The Kafka topic to which to write.\n\n| `spring.batch.job.kafkaitemwriter.delete`\n| `boolean`\n| `false`\n| Whether the items being passed to the writer are all to be sent as delete events to the topic.\n|===\n\nFor more about the configuration options for the `KafkaItemWriter`, see the  https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/kafka/KafkaItemWriter.html[`KafkaItemWiter` documentation].\n\n[[spring-aot]]\n=== Spring AOT\nWhen using Spring AOT with Single Step Batch Starter you must set the reader and\nwriter name properties at compile time (unless you create a bean(s) for the reader and or writer).\nTo do this you must include the name of the reader and writer that you wish to use as\nand argument or environment variable in the boot maven plugin or gradle plugin.   For example if\nyou wish to enable the `FlatFileItemReader` and `FlatFileItemWriter` in Maven it would look like:\n\n```\n    <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n        <executions>\n            <execution>\n            <id>process-aot</id>\n            <goals>\n                <goal>process-aot</goal>\n            </goals>\n            </execution>\n        </executions>\n        <configuration>\n            <arguments>\n                <argument>--spring.batch.job.flatfileitemreader.name=foobar</argument>\n                <argument>--spring.batch.job.flatfileitemwriter.name=fooWriter</argument>\n            </arguments>\n        </configuration>\n    </plugin>\n```\n"
  },
  {
    "path": "docs/modules/ROOT/pages/batch.adoc",
    "content": "\n[[batch]]\n= Batch\n\n[[partintro]]\n--\nThis section goes into more detail about Spring Cloud Task's integration with Spring\nBatch. Tracking the association between a job execution and the task in which it was\nexecuted.\n\n--\n\n[[batch-association]]\n== Associating a Job Execution to the Task in which It Was Executed\n\nSpring Boot provides facilities for the execution of batch jobs within a Spring Boot Uber-jar.\nSpring Boot's support of this functionality lets a developer execute multiple batch jobs\nwithin that execution. Spring Cloud Task provides the ability to associate the execution\nof a job (a job execution) with a task's execution so that one can be traced back to the\nother.\n\nSpring Cloud Task achieves this functionality by using the `TaskBatchExecutionListener`.\nBy default,\nthis listener is auto configured in any context that has both a Spring Batch Job\nconfigured (by having a bean of type `Job` defined in the context) and the\n`spring-cloud-task-batch` jar on the classpath. The listener is injected into all jobs\nthat meet those conditions.\n\n[[batch-association-override]]\n=== Overriding the TaskBatchExecutionListener\n\nTo prevent the listener from being injected into any batch jobs within the current\ncontext, you can disable the autoconfiguration by using standard Spring Boot mechanisms.\n\nTo only have the listener injected into particular jobs within the context, override the\n`batchTaskExecutionListenerBeanPostProcessor` and provide a list of job bean IDs, as shown\nin the following example:\n\n[source,java]\n----\npublic static TaskBatchExecutionListenerBeanPostProcessor batchTaskExecutionListenerBeanPostProcessor() {\n\tTaskBatchExecutionListenerBeanPostProcessor postProcessor =\n\t\tnew TaskBatchExecutionListenerBeanPostProcessor();\n\n\tpostProcessor.setJobNames(Arrays.asList(new String[] {\"job1\", \"job2\"}));\n\n\treturn postProcessor;\n}\n----\n\nNOTE: You can find a sample batch application in the samples module of the Spring Cloud\nTask Project,\nhttps://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/batch-job[here].\n\n[[batch-informational-messages]]\n== Batch Informational Messages\n\nSpring Cloud Task provides the ability for batch jobs to emit informational messages. The\n\"`xref:stream.adoc#stream-integration-batch-events[Spring Batch Events]`\" section covers this feature in detail.\n\n[[batch-failures-and-tasks]]\n== Batch Job Exit Codes\n\nAs discussed xref:features.adoc#features-lifecycle-exit-codes[earlier], Spring Cloud Task\napplications support the ability to record the exit code of a task execution. However, in\ncases where you run a Spring Batch Job within a task, regardless of how the Batch Job\nExecution completes, the result of the task is always zero when using the default\nBatch/Boot behavior. Keep in mind that a task is a boot application and that the exit code\nreturned from the task is the same as a boot application.\nTo override this behavior and allow the task to return an exit code other than zero when a\nbatch job returns an\nhttps://docs.spring.io/spring-batch/current/reference/html/step.html#batchStatusVsExitStatus[BatchStatus]\nof `FAILED`, set `spring.cloud.task.batch.fail-on-job-failure` to `true`. Then the exit code\ncan be 1 (the default) or be based on the\nhttps://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-application-exit[specified\n`ExitCodeGenerator`])\n\nThis functionality uses a new `ApplicationRunner` that replaces the one provided by Spring\nBoot. By default, it is configured with the same order. However, if you want to customize\nthe order in which the `ApplicationRunner` is run, you can set its order by setting the\n`spring.cloud.task.batch.applicationRunnerOrder` property. To have your task return the\nexit code based on the result of the batch job execution, you need to write your own\n`CommandLineRunner`.\n//TODO Great place for a example showing how a custom CommandLineRunner\n"
  },
  {
    "path": "docs/modules/ROOT/pages/configprops.adoc",
    "content": "[[configuration-properties]]\n= Configuration Properties\n\nBelow you can find a list of configuration properties.\n\ninclude::partial$_configprops.adoc[]\n"
  },
  {
    "path": "docs/modules/ROOT/pages/features.adoc",
    "content": "\n[[features]]\n= Features\n\n[[partintro]]\n--\nThis section goes into more detail about Spring Cloud Task, including how to use it, how\nto configure it, and the appropriate extension points.\n--\n\n[[features-lifecycle]]\n== The lifecycle of a Spring Cloud Task\n\nIn most cases, the modern cloud environment is designed around the execution of processes\nthat are not expected to end. If they do end, they are typically restarted. While most\nplatforms do have some way to run a process that is not restarted when it ends, the\nresults of that run are typically not maintained in a consumable way. Spring Cloud\nTask offers the ability to execute short-lived processes in an environment and record the\nresults. Doing so allows for a microservices architecture around short-lived processes as\nwell as longer running services through the integration of tasks by messages.\n\nWhile this functionality is useful in a cloud environment, the same issues can arise in a\ntraditional deployment model as well. When running Spring Boot applications with a\nscheduler such as cron, it can be useful to be able to monitor the results of the\napplication after its completion.\n\nSpring Cloud Task takes the approach that a Spring Boot application can have a start and\nan end and still be successful. Batch applications are one example of how processes that\nare expected to end (and that are often short-lived) can be helpful.\n\nSpring Cloud Task records the lifecycle events of a given task. Most long-running\nprocesses, typified by most web applications, do not save their lifecycle events. The\ntasks at the heart of Spring Cloud Task do.\n\nThe lifecycle consists of a single task execution. This is a physical execution of a\nSpring Boot application configured to be a task (that is, it has the Sprint Cloud Task dependencies).\n\nAt the beginning of a task, before any `CommandLineRunner` or `ApplicationRunner`\nimplementations have been run, an entry in the `TaskRepository` that records the start\nevent is created. This event is triggered through `SmartLifecycle#start` being triggered\nby the Spring Framework. This indicates to the system that all beans are ready for use and\ncomes before running any of the `CommandLineRunner` or `ApplicationRunner` implementations\nprovided by Spring Boot.\n\nNOTE: The recording of a task only occurs upon the successful bootstrapping of an\n`ApplicationContext`. If the context fails to bootstrap at all, the task's run is not\nrecorded.\n\nUpon completion of all of the `*Runner#run` calls from Spring Boot or the failure of an\n`ApplicationContext` (indicated by an `ApplicationFailedEvent`), the task execution is\nupdated in the repository with the results.\n\nNOTE: If the application requires the `ApplicationContext` to be closed at the\ncompletion of a task (all `*Runner#run` methods have been called and the task\nrepository has been updated), set the property `spring.cloud.task.closecontextEnabled`\nto true.\n\n[[features-task-execution-details]]\n=== The TaskExecution\n\nThe information stored in the `TaskRepository` is modeled in the `TaskExecution` class and\nconsists of the following information:\n\n|===\n|Field |Description\n\n|`executionid`\n|The unique ID for the task's run.\n\n|`exitCode`\n|The exit code generated from an `ExitCodeExceptionMapper` implementation. If there is no\nexit code generated but an `ApplicationFailedEvent` is thrown, 1 is set.  Otherwise, it is\nassumed to be 0.\n\n|`taskName`\n|The name for the task, as determined by the configured `TaskNameResolver`.\n\n|`startTime`\n|The time the task was started, as indicated by the `SmartLifecycle#start` call.\n\n|`endTime`\n|The time the task was completed, as indicated by the `ApplicationReadyEvent`.\n\n|`exitMessage`\n|Any information available at the time of exit. This can programmatically be set by a\n`TaskExecutionListener`.\n\n|`errorMessage`\n|If an exception is the cause of the end of the task (as indicated by an\n`ApplicationFailedEvent`), the stack trace for that exception is stored here.\n\n|`arguments`\n|A `List` of the string command line arguments as they were passed into the executable\nboot application.\n|===\n\n[[features-lifecycle-exit-codes]]\n=== Mapping Exit Codes\n\nWhen a task completes, it tries to return an exit code to the OS. If we take a look\nat our xref:getting-started.adoc#getting-started-developing-first-task[original example], we can see that we are\nnot controlling that aspect of our application. So, if an exception is thrown, the JVM\nreturns a code that may or may not be of any use to you in debugging.\n\nConsequently, Spring Boot provides an interface, `ExitCodeExceptionMapper`, that lets you\nmap uncaught exceptions to exit codes. Doing so lets you indicate, at the level of exit\ncodes, what went wrong. Also, by mapping exit codes in this manner, Spring Cloud Task\nrecords the returned exit code.\n\nIf the task terminates with a SIG-INT or a SIG-TERM, the exit code is zero unless\notherwise specified within the code.\n\nNOTE: While the task is running, the exit code is stored as a null in the repository.\nOnce the task completes, the appropriate exit code is stored based on the guidelines described\nearlier in this section.\n\n[[features-configuration]]\n== Configuration\n\nSpring Cloud Task provides a ready-to-use configuration, as defined in the\n`DefaultTaskConfigurer` and `SimpleTaskConfiguration` classes. This section walks through\nthe defaults and how to customize Spring Cloud Task for your needs.\n\n[[features-data-source]]\n=== DataSource\n\nSpring Cloud Task uses a datasource for storing the results of task executions. By\ndefault, we provide an in-memory instance of H2 to provide a simple method of\nbootstrapping development. However, in a production environment, you probably want to\nconfigure your own `DataSource`.\n\nIf your application uses only a single `DataSource` and that serves as both your business\nschema and the task repository, all you need to do is provide any `DataSource` (the\neasiest way to do so is through Spring Boot's configuration conventions).  This\n`DataSource` is automatically used by Spring Cloud Task for the repository.\n\nIf your application uses more than one `DataSource`, you need to configure the task\nrepository with the appropriate `DataSource`. This customization can be done through an\nimplementation of  `TaskConfigurer`.\n\n[[features-table-prefix]]\n=== Table Prefix\nOne modifiable property of `TaskRepository` is the table prefix for the task tables. By\ndefault, they are all prefaced with `TASK_`. `TASK_EXECUTION` and `TASK_EXECUTION_PARAMS`\nare two examples. However, there are potential reasons to modify this prefix. If the\nschema name needs to be prepended to the table names or if more than one set of task\ntables is needed within the same schema, you must change the table prefix. You can do so\nby setting the `spring.cloud.task.tablePrefix` to the prefix you need, as follows:\n\n`spring.cloud.task.tablePrefix=yourPrefix`\n\nBy using the `spring.cloud.task.tablePrefix`, a user assumes the responsibility to\ncreate the task tables that meet both the criteria for the task table schema but\nwith modifications that are required for a user's business needs.\nYou can utilize the Spring Cloud Task Schema DDL as a guide when creating your own Task DDL as seen\nhttps://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task[here].\n\n\n[[features-table-initialization]]\n=== Enable/Disable table initialization\nIn cases where you are creating the task tables and do not wish for Spring Cloud Task to\ncreate them at task startup, set the `spring.cloud.task.initialize-enabled` property to\n`false`, as follows:\n\n`spring.cloud.task.initialize-enabled=false`\n\nIt defaults to `true`.\n\nNOTE: The property `spring.cloud.task.initialize.enable` has been deprecated.\n\n[[features-generated_task_id]]\n=== Externally Generated Task ID\n\nIn some cases, you may want to allow for the time difference between when a task is\nrequested and when the infrastructure actually launches it. Spring Cloud Task lets you\ncreate a `TaskExecution` when the task is requested. Then pass the execution ID of the\ngenerated `TaskExecution` to the task so that it can update the `TaskExecution` through\nthe task's lifecycle.\n\nA `TaskExecution` can be created by calling the `createTaskExecution` method on an\nimplementation of the `TaskRepository` that references the datastore that holds\nthe `TaskExecution` objects.\n\nIn order to configure your Task to use a generated `TaskExecutionId`, add the\nfollowing property:\n\n`spring.cloud.task.executionid=yourtaskId`\n\n[[features-external_task_id]]\n=== External Task Id\n\nSpring Cloud Task lets you store an external task ID for each\n`TaskExecution`.  In order to configure your Task to use a generated `TaskExecutionId`, add the\nfollowing property:\n\n`spring.cloud.task.external-execution-id=<externalTaskId>`\n\n[[features-parent_task_id]]\n=== Parent Task Id\n\nSpring Cloud Task lets you store a parent task ID for each `TaskExecution`. An example of\nthis would be a task that executes another task or tasks and you want to record which task\nlaunched each of the child tasks. In order to configure your Task to set a parent\n`TaskExecutionId` add the following property on the child task:\n\n`spring.cloud.task.parent-execution-id=<parentExecutionTaskId>`\n\n[[features-task-configurer]]\n=== TaskConfigurer\n\nThe `TaskConfigurer` is a strategy interface that lets you customize the way components of\nSpring Cloud Task are configured. By default, we provide the `DefaultTaskConfigurer` that\nprovides logical defaults: `Map`-based in-memory components (useful for development if no\n`DataSource` is provided) and JDBC based components (useful if there is a `DataSource`\navailable).\n\nThe `TaskConfigurer` lets you configure three main components:\n\n|===\n|Component |Description |Default (provided by `DefaultTaskConfigurer`)\n\n|`TaskRepository`\n|The implementation of the `TaskRepository` to be used.\n|`SimpleTaskRepository`\n\n|`TaskExplorer`\n|The implementation of the `TaskExplorer` (a component for read-only access to the task\nrepository) to be used.\n|`SimpleTaskExplorer`\n\n|`PlatformTransactionManager`\n|A transaction manager to be used when running updates for tasks.\n|`JdbcTransactionManager` if a `DataSource` is used.\n`ResourcelessTransactionManager` if it is not.\n|===\n\nYou can customize any of the components described in the preceding table by creating a\ncustom implementation of the `TaskConfigurer` interface. Typically, extending the\n`DefaultTaskConfigurer` (which is provided if a `TaskConfigurer` is not found) and\noverriding the required getter is sufficient. However, implementing your own from scratch\nmay be required.\n\nNOTE: Users should not directly use getter methods from a `TaskConfigurer` directly\nunless they are using it to supply implementations to be exposed as Spring Beans.\n\n[[features-task-execution-listener]]\n=== Task Execution Listener\n\n`TaskExecutionListener` lets you register listeners for specific events that occur during\nthe task lifecycle. To do so, create a class that implements the\n`TaskExecutionListener` interface. The class that implements the `TaskExecutionListener`\ninterface is notified of the following events:\n\n* `onTaskStartup`: Prior to storing the `TaskExecution` into the `TaskRepository`.\n* `onTaskEnd`: Prior to updating the `TaskExecution` entry in the `TaskRepository` and\nmarking the final state of the task.\n* `onTaskFailed`: Prior to the `onTaskEnd` method being invoked when an unhandled\nexception is thrown by the task.\n\nSpring Cloud Task also lets you add `TaskExecution` Listeners to methods within a bean\nby using the following method annotations:\n\n* `@BeforeTask`: Prior to the storing the `TaskExecution` into the `TaskRepository`\n* `@AfterTask`: Prior to the updating of the `TaskExecution` entry in the `TaskRepository`\nmarking the final state of the task.\n* `@FailedTask`: Prior to the `@AfterTask` method being invoked when an unhandled\nexception is thrown by the task.\n\nThe following example shows the three annotations in use:\n\n[source,java]\n----\n public class MyBean {\n\n\t@BeforeTask\n\tpublic void methodA(TaskExecution taskExecution) {\n\t}\n\n\t@AfterTask\n\tpublic void methodB(TaskExecution taskExecution) {\n\t}\n\n\t@FailedTask\n\tpublic void methodC(TaskExecution taskExecution, Throwable throwable) {\n\t}\n}\n----\n\nNOTE: Inserting an `ApplicationListener` earlier in the chain than `TaskLifecycleListener` exists may cause unexpected effects.\n\n[[features-task-execution-listener-Exceptions]]\n==== Exceptions Thrown by Task Execution Listener\nIf an exception is thrown by a `TaskExecutionListener` event handler, all listener\nprocessing for that event handler stops.  For example, if three `onTaskStartup` listeners\nhave started and the first `onTaskStartup` event handler throws an exception, the other\ntwo `onTaskStartup` methods are not called. However, the other event handlers (`onTaskEnd`\nand `onTaskFailed`) for the `TaskExecutionListeners` are called.\n\nThe exit code returned when a exception is thrown by a `TaskExecutionListener`\nevent handler is the exit code that was reported by the\nhttps://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/ExitCodeEvent.html[ExitCodeEvent].\nIf no `ExitCodeEvent` is emitted, the Exception thrown is evaluated to see\nif it is of type\nhttps://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-application-exit[ExitCodeGenerator].\nIf so, it returns the exit code from  the `ExitCodeGenerator`. Otherwise, `1`\nis returned.\n\nIn the case that an exception is thrown in an `onTaskStartup` method, the exit code for the application will be `1`.\nIf an exception is thrown in either a `onTaskEnd` or `onTaskFailed`\nmethod, the exit code for the application will be the one established using the rules enumerated above.\n\nNOTE: In the case of an exception being thrown in a `onTaskStartup`, `onTaskEnd`, or `onTaskFailed`\nyou can not override the exit code for the application using `ExitCodeExceptionMapper`.\n\n\n\n[[features-task-execution-listener-exit-messages]]\n==== Exit Messages\n\nYou can set the exit message for a task programmatically by using a\n`TaskExecutionListener`. This is done by setting the `TaskExecution's` `exitMessage`,\nwhich then gets passed into the `TaskExecutionListener`. The following example shows\na method that is annotated with the `@AfterTask` `ExecutionListener` :\n\n[source,java]\n@AfterTask\npublic void afterMe(TaskExecution taskExecution) {\n    taskExecution.setExitMessage(\"AFTER EXIT MESSAGE\");\n}\n\nAn `ExitMessage` can be set at any of the listener events (`onTaskStartup`,\n`onTaskFailed`, and `onTaskEnd`). The order of precedence for the three listeners follows:\n\n. `onTaskEnd`\n. `onTaskFailed`\n. `onTaskStartup`\n\nFor example, if you set an `exitMessage` for the `onTaskStartup` and `onTaskFailed`\nlisteners and the task ends without failing, the `exitMessage` from the `onTaskStartup`\nis stored in the repository. Otherwise, if a failure occurs, the `exitMessage` from\nthe `onTaskFailed` is stored. Also if you set the `exitMessage` with an\n`onTaskEnd` listener, the `exitMessage` from the `onTaskEnd` supersedes\nthe exit messages from both the `onTaskStartup` and `onTaskFailed`.\n\n[[features-single-instance-enabled]]\n=== Restricting Spring Cloud Task Instances\n\nSpring Cloud Task lets you establish that only one task with a given task name can be run\nat a time. To do so, you need to establish the <<features-task-name, task name>> and set\n`spring.cloud.task.single-instance-enabled=true` for each task execution. While the first\ntask execution is running, any other time you try to run a task with the same\n<<features-task-name, task name>> and `spring.cloud.task.single-instance-enabled=true`, the\ntask fails with the following error message: `Task with name \"application\" is already\nrunning.` The default value for `spring.cloud.task.single-instance-enabled` is `false`. The\nfollowing example shows how to set `spring.cloud.task.single-instance-enabled` to `true`:\n\n`spring.cloud.task.single-instance-enabled=true or false`\n\nTo use this feature, you must add the following Spring Integration dependencies to your\napplication:\n\n[source,xml]\n<dependency>\n    <groupId>org.springframework.integration</groupId>\n    <artifactId>spring-integration-core</artifactId>\n</dependency>\n<dependency>\n    <groupId>org.springframework.integration</groupId>\n    <artifactId>spring-integration-jdbc</artifactId>\n</dependency>\n\nNOTE: The exit code for the application will be 1 if the task fails because this feature\nis enabled and another task is running with the same task name.\n\n[[single-instance-usage-for-spring-aot-and-native-compilation]]\n==== Single Instance Usage for Spring AOT And Native Compilation\nTo use Spring Cloud Task's single-instance feature when creating a natively compiled app, you need to enable the feature at build time.\nTo do so, add the process-aot execution and set `spring.cloud.task.single-step-instance-enabled=true` as a JVM argument, as follows:\n[source,xml]\n<plugin>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-maven-plugin</artifactId>\n    <executions>\n        <execution>\n            <id>process-aot</id>\n            <goals>\n                <goal>process-aot</goal>\n            </goals>\n            <configuration>\n                <jvmArguments>\n                    -Dspring.cloud.task.single-instance-enabled=true\n                </jvmArguments>\n            </configuration>\n        </execution>\n    </executions>\n</plugin>\n\n[[enabling-observations-for-applicationrunner-and-commandlinerunner]]\n=== Enabling  Observations for ApplicationRunner and CommandLineRunner\n\n\nTo Enable Task Observations for `ApplicationRunner` or `CommandLineRunner` set `spring.cloud.task.observation.enabled` to true.\n\nAn example task application with observations enables using the `SimpleMeterRegistry` can be found https://github.com/spring-cloud/spring-cloud-task/tree/main/spring-cloud-task-samples/task-observations[here].\n\n[[disabling-spring-cloud-task-auto-configuration]]\n=== Disabling Spring Cloud Task Auto Configuration\n\nIn cases where Spring Cloud Task should not be autoconfigured for an implementation, you can disable Task's auto configuration.\nThis can be done either by adding the following annotation to your Task application:\n```\n@EnableAutoConfiguration(exclude={SimpleTaskAutoConfiguration.class})\n```\nYou may also disable Task auto configuration by setting the `spring.cloud.task.autoconfiguration.enabled` property to `false`.\n\n[[closing-the-context]]\n=== Closing the Context\nIf the application requires the `ApplicationContext` to be closed at the\ncompletion of a task (all `*Runner#run` methods have been called and the task\nrepository has been updated), set the property `spring.cloud.task.closecontextEnabled`\nto `true`.\n\nAnother case to close the context is when the Task Execution completes however the application does not terminate.\nIn these cases the context is held open because a thread has been allocated\n(for example: if you are using a TaskExecutor). In these cases\nset the `spring.cloud.task.closecontextEnabled` property to `true` when launching your task.\nThis will close the application's context once the task is complete.\nThus allowing the application to terminate.\n\n[[enable-task-metrics]]\n=== Enable Task Metrics\nSpring Cloud Task integrates with Micrometer and creates observations for the Tasks it executes.\nTo enable Task Observability integration, you must add `spring-boot-starter-actuator`, your preferred registry implementation (if you want to publish metrics), and micrometer-tracing (if you want to publish tracing data) to your task application.\nAn example maven set of dependencies to enable task observability and metrics using Influx would be:\n\n[source,xml]\n<dependency>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-actuator</artifactId>\n</dependency>\n<dependency>\n    <groupId>io.micrometer</groupId>\n    <artifactId>micrometer-registry-influx</artifactId>\n    <scope>runtime</scope>\n</dependency>\n\n[[spring-task-and-spring-cloud-task]]\n=== Spring Task and Spring Cloud Task Properties\n\nThe term `task` is frequently used word in the industry. In one such example Spring Boot offers the `spring.task` while Spring Cloud Task offers the `spring.cloud.task` properties.\nThis has caused some confusion in the past that these two groups of properties are directly related.   However, they represent 2 different set of features offered in the Spring ecosystem.\n\n* `spring.task` refers to the properties that configure the `ThreadPoolTaskScheduler`.\n* `spring.cloud.task` refers to the properties that configure features of Spring Cloud Task.\n"
  },
  {
    "path": "docs/modules/ROOT/pages/getting-started.adoc",
    "content": "\n[[getting-started]]\n= Getting started\n\n[[partintro]]\n--\nIf you are just getting started with Spring Cloud Task, you should read this section.\nHere, we answer the basic \"`what?`\", \"`how?`\", and \"`why?`\" questions. We start with a\ngentle introduction to Spring Cloud Task. We then build a Spring Cloud Task application,\ndiscussing some core principles as we go.\n--\n\n[[getting-started-introducing-spring-cloud-task]]\n== Introducing Spring Cloud Task\n\nSpring Cloud Task makes it easy to create short-lived microservices. It provides\ncapabilities that let short-lived JVM processes be executed on demand in a production\nenvironment.\n\n[[getting-started-system-requirements]]\n== System Requirements\n\nYou need to have Java installed (Java 17 or better).\n\n[[database-requirements]]\n=== Database Requirements\n\nSpring Cloud Task uses a relational database to store the results of an executed task.\nWhile you can begin developing a task without a database (the status of the task is logged\nas part of the task repository's updates), for production environments, you want to\nuse a supported database. Spring Cloud Task currently supports the following databases:\n\n* DB2\n* H2\n* HSQLDB\n* MySql\n* Oracle\n* Postgres\n* SqlServer\n\n[[getting-started-developing-first-task]]\n== Developing Your First Spring Cloud Task Application\n\nA good place to start is with a simple \"`Hello, World!`\" application, so we create the\nSpring Cloud Task equivalent to highlight the features of the framework. Most IDEs have\ngood support for Apache Maven, so we use it as the build tool for this project.\n\nNOTE: The spring.io web site contains many https://spring.io/guides[“`Getting Started`”\nguides] that use Spring Boot. If you need to solve a specific problem, check there first.\nYou can shortcut the following steps by going to the\nhttps://start.spring.io/[Spring Initializr] and creating a new project. Doing so\nautomatically generates a new project structure so that you can start coding right away.\nWe recommend experimenting with the Spring Initializr to become familiar with it.\n\n[[getting-started-creating-project]]\n=== Creating the Spring Task Project using Spring Initializr\nNow we can create and test an application that prints `Hello, World!` to the console.\n\nTo do so:\n\n. Visit the link:https://start.spring.io/[Spring Initialzr] site.\n.. Create a new Maven project with a *Group* name of `io.spring.demo` and an *Artifact* name of `helloworld`.\n.. In the Dependencies text box, type `task` and then select the `Task` dependency with the `Spring Cloud` label.\n.. In the Dependencies text box, type `h2` and then select the `H2` dependency with the `SQL` label.\n.. Click the *Generate Project* button\n. Unzip the helloworld.zip file and import the project into your favorite IDE.\n\n[[getting-started-writing-the-code]]\n=== Writing the Code\n\nTo finish our application, we need to update the generated `HelloworldApplication` with the following contents so that it launches a Task.\n[source,java]\n----\npackage io.spring.demo.helloworld;\n\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\n@EnableTask\npublic class HelloworldApplication {\n\n\t@Bean\n\tpublic ApplicationRunner applicationRunner() {\n\t\treturn new HelloWorldApplicationRunner();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(HelloworldApplication.class, args);\n\t}\n\n\tpublic static class HelloWorldApplicationRunner implements ApplicationRunner {\n\n\t\t@Override\n\t\tpublic void run(ApplicationArguments args) throws Exception {\n\t\t\tSystem.out.println(\"Hello, World!\");\n\n\t\t}\n\t}\n}\n----\n\nWhile it may seem small, quite a bit is going on. For more about Spring\nBoot specifics, see the\nhttps://docs.spring.io/spring-boot/docs/current/reference/html/[Spring Boot reference documentation].\n\nNow we can open the `application.properties` file in `src/main/resources`.\nWe need to configure two properties in `application.properties`:\n\n* `application.name`: To set the application name (which is translated to the task name)\n* `logging.level`: To set the logging for Spring Cloud Task to `DEBUG` in order to\nget a view of what is going on.\n\nThe following example shows how to do both:\n\n\n[source]\n----\nlogging.level.org.springframework.cloud.task=DEBUG\nspring.application.name=helloWorld\n----\n\n[[getting-started-at-task]]\n==== Task Auto Configuration\n\nWhen including Spring Cloud Task Starter dependency, Task auto configures all beans to bootstrap it's functionality.\nPart of this configuration registers the `TaskRepository` and the infrastructure for its use.\n\nIn our demo, the `TaskRepository` uses an embedded H2 database to record the results\nof a task. This H2 embedded database is not a practical solution for a production environment, since\nthe H2 DB goes away once the task ends. However, for a quick getting-started\nexperience, we can use this in our example as well as echoing to the logs what is being updated\nin that repository. In the xref:features.adoc#features-configuration[Configuration] section (later in this\ndocumentation), we cover how to customize the configuration of the pieces provided by\nSpring Cloud Task.\n\nWhen our sample application runs, Spring Boot launches our `HelloWorldApplicationRunner`\nand outputs our \"`Hello, World!`\" message to standard out. The `TaskLifecycleListener`\nrecords the start of the task and the end of the task in the repository.\n\n[[getting-started-main-method]]\n==== The main method\n\nThe main method serves as the entry point to any java application.  Our main method\ndelegates to Spring Boot's https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html[SpringApplication] class.\n\n[[getting-started-clr]]\n==== The ApplicationRunner\n\nSpring includes many ways to bootstrap an application's logic. Spring Boot provides\na convenient method of doing so in an organized manner through its `*Runner` interfaces\n(`CommandLineRunner` or `ApplicationRunner`). A well behaved task can bootstrap any\nlogic by using one of these two runners.\n\nThe lifecycle of a task is considered from before the `*Runner#run` methods are executed\nto once they are all complete. Spring Boot lets an application use multiple\n`*Runner` implementations, as does Spring Cloud Task.\n\nNOTE: Any processing bootstrapped from mechanisms other than a `CommandLineRunner` or\n`ApplicationRunner` (by using `InitializingBean#afterPropertiesSet` for example) is not\n recorded by Spring Cloud Task.\n\n[[getting-started-running-the-example]]\n=== Running the Example\n\nAt this point, our application should work.  Since this application is Spring Boot-based,\nwe can run it from the command line by using `$ ./mvnw spring-boot:run` from the root\nof our application, as shown (with its output) in the following example:\n\n[source]\n----\n$ mvn clean spring-boot:run\n....... . . .\n....... . . . (Maven log output here)\n....... . . .\n\n  .   ____          _            __ _ _\n /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\\n( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\\n \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )\n  '  |____| .__|_| |_|_| |_\\__, | / / / /\n =========|_|==============|___/=/_/_/_/\n :: Spring Boot ::                (v3.3.0)\n\n2024-01-04T10:07:01.102-06:00  INFO 18248 --- [helloWorld] [           main] i.s.d.helloworld.HelloworldApplication   : Starting HelloworldApplication using Java 21.0.1 with PID 18248 (/Users/dashaun/fun/dashaun/spring-cloud-task/helloworld/target/classes started by dashaun in /Users/dashaun/fun/dashaun/spring-cloud-task/helloworld)\n2024-01-04T10:07:01.103-06:00  INFO 18248 --- [helloWorld] [           main] i.s.d.helloworld.HelloworldApplication   : No active profile set, falling back to 1 default profile: \"default\"\n2024-01-04T10:07:01.526-06:00  INFO 18248 --- [helloWorld] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...\n2024-01-04T10:07:01.626-06:00  INFO 18248 --- [helloWorld] [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:3ad913f8-59ce-4785-bf8e-d6335dff6856 user=SA\n2024-01-04T10:07:01.627-06:00  INFO 18248 --- [helloWorld] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.\n2024-01-04T10:07:01.633-06:00 DEBUG 18248 --- [helloWorld] [           main] o.s.c.t.c.SimpleTaskAutoConfiguration    : Using org.springframework.cloud.task.configuration.DefaultTaskConfigurer TaskConfigurer\n2024-01-04T10:07:01.633-06:00 DEBUG 18248 --- [helloWorld] [           main] o.s.c.t.c.DefaultTaskConfigurer          : No EntityManager was found, using DataSourceTransactionManager\n2024-01-04T10:07:01.639-06:00 DEBUG 18248 --- [helloWorld] [           main] o.s.c.t.r.s.TaskRepositoryInitializer    : Initializing task schema for h2 database\n2024-01-04T10:07:01.772-06:00 DEBUG 18248 --- [helloWorld] [           main] o.s.c.t.r.support.SimpleTaskRepository   : Creating: TaskExecution{executionId=0, parentExecutionId=null, exitCode=null, taskName='helloWorld', startTime=2024-01-04T10:07:01.757268, endTime=null, exitMessage='null', externalExecutionId='null', errorMessage='null', arguments=[]}\n2024-01-04T10:07:01.785-06:00  INFO 18248 --- [helloWorld] [           main] i.s.d.helloworld.HelloworldApplication   : Started HelloworldApplication in 0.853 seconds (process running for 1.029)\nHello, World!\n2024-01-04T10:07:01.794-06:00 DEBUG 18248 --- [helloWorld] [           main] o.s.c.t.r.support.SimpleTaskRepository   : Updating: TaskExecution with executionId=1 with the following {exitCode=0, endTime=2024-01-04T10:07:01.787112, exitMessage='null', errorMessage='null'}\n2024-01-04T10:07:01.799-06:00  INFO 18248 --- [helloWorld] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...\n2024-01-04T10:07:01.806-06:00  INFO 18248 --- [helloWorld] [ionShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.\n\n....... . . .\n....... . . . (Maven log output here)\n....... . . .\n----\n\nThe preceding output has three lines that are of interest to us here:\n\n* `SimpleTaskRepository` logged the creation of the entry in the `TaskRepository`.\n* The execution of our `ApplicationRunner`, demonstrated by the \"`Hello, World!`\" output.\n* `SimpleTaskRepository` logs the completion of the task in the `TaskRepository`.\n\nNOTE: A simple task application can be found in the samples module of the Spring Cloud\nTask Project\nhttps://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/timestamp[here].\n"
  },
  {
    "path": "docs/modules/ROOT/pages/index.adoc",
    "content": "[[spring-cloud-task-reference-guide]]\n= Spring Cloud Task Reference Guide\n\nMichael Minella, Glenn Renfro, Jay Bryant\n\n:page-section-summary-toc: 1\n\ninclude::preface.adoc[leveloffset=1]\n\n// ======================================================================================\n\nVersion {project-version}\n\n(C) 2009-2022 VMware, Inc. All rights reserved.\n\nCopies of this document may be made for your own use and for distribution to\nothers, provided that you do not charge any fee for such copies and further\nprovided that each copy contains this Copyright Notice, whether distributed in\nprint or electronically.\n\n\n\n\n\n\n\n\n// ======================================================================================\n"
  },
  {
    "path": "docs/modules/ROOT/pages/observability.adoc",
    "content": "[[observability]]\n= Observability\n\n== Observability metadata\n\ninclude::partial$_metrics.adoc[]\n\ninclude::partial$_spans.adoc[]\n"
  },
  {
    "path": "docs/modules/ROOT/pages/preface.adoc",
    "content": "[[preface]]\n= Preface\n\n[[task-documentation-about]]\n\nThis section provides a brief overview of the Spring Cloud Task reference documentation.\nThink of it as a map for the rest of the document. You can read this reference guide in a\nlinear fashion or you can skip sections if something does not interest you.\n\n[[about-the-documentation]]\n== About the documentation\nThe Spring Cloud Task reference guide is available in https://docs.spring.io/spring-cloud-task/docs/current/reference[html].\nThe latest copy is available at\nhttps://docs.spring.io/spring-cloud-task/reference/.\n\nCopies of this document may be made for your own use and for distribution to others,\nprovided that you do not charge any fee for such copies and further provided that each\ncopy contains this Copyright Notice, whether distributed in print or electronically.\n\n[[task-documentation-getting-help]]\n== Getting help\nHaving trouble with Spring Cloud Task? We would like to help!\n\n* Ask a question. We monitor https://stackoverflow.com[stackoverflow.com] for questions\ntagged with https://stackoverflow.com/tags/spring-cloud-task[`spring-cloud-task`].\n* Report bugs with Spring Cloud Task at\nhttps://github.com/spring-cloud/spring-cloud-task/issues.\n\nNOTE: All of Spring Cloud Task is open source, including the documentation. If you find\na problem with the docs or if you just want to improve them, please {github-code}[get\ninvolved].\n\n[[task-documentation-first-steps]]\n== First Steps\nIf you are just getting started with Spring Cloud Task or with 'Spring' in general, we\nsuggesting reading the xref:getting-started.adoc[Getting started] chapter.\n\nTo get started from scratch, read the following sections:\n\n* xref:getting-started.adoc#getting-started-introducing-spring-cloud-task[Introducing Spring Cloud Task]\n* xref:getting-started.adoc#getting-started-system-requirements[System Requirements] +\n\nTo follow the tutorial, read\nxref:getting-started.adoc#getting-started-developing-first-task[Developing Your First Spring Cloud Task Application] +\nTo run your example, read\nxref:getting-started.adoc#getting-started-running-the-example[Running the Example]\n"
  },
  {
    "path": "docs/modules/ROOT/pages/stream.adoc",
    "content": "[[stream-integration]]\n= Spring Cloud Stream Integration\n\n[[partintro]]\n--\nA task by itself can be useful, but integration of a task into a larger ecosystem lets it\nbe useful for more complex processing and orchestration. This section\ncovers the integration options for Spring Cloud Task with Spring Cloud Stream.\n--\n\n[[stream-integration-events]]\n== Spring Cloud Task Events\n\nSpring Cloud Task provides the ability to emit events through a Spring Cloud Stream\nchannel when the task is run through a Spring Cloud Stream channel. A task listener is\nused to publish the `TaskExecution` on a message channel named `task-events`. This feature\nis autowired into any task that has `spring-cloud-stream`, `spring-cloud-stream-<binder>`,\nand a defined task on its classpath.\n\nNOTE: To disable the event emitting listener, set the `spring.cloud.task.events.enabled`\nproperty to `false`.\n\nWith the appropriate classpath defined, the following task emits the `TaskExecution` as an\nevent on the `task-events` channel (at both the start and the end of the task):\n\n[source, java]\n----\n@SpringBootApplication\npublic class TaskEventsApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(TaskEventsApplication.class, args);\n\t}\n\n\t@Configuration\n\tpublic static class TaskConfiguration {\n\n\t\t@Bean\n\t\tpublic ApplicationRunner applicationRunner() {\n\t\t\treturn new ApplicationRunner() {\n\t\t\t\t@Override\n\t\t\t\tpublic void run(ApplicationArguments args) {\n\t\t\t\t\tSystem.out.println(\"The ApplicationRunner was executed\");\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n}\n----\n\nNOTE: A binder implementation is also required to be on the classpath.\n\nNOTE: A sample task event application can be found in the samples module\nof the Spring Cloud Task Project,\nhttps://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/task-events[here].\n\n[[stream-integration-disable-task-events]]\n=== Disabling Specific Task Events\n\nTo disable task events, you can set the `spring.cloud.task.events.enabled` property to\n`false`.\n\n[[stream-integration-batch-events]]\n== Spring Batch Events\n\nWhen executing a Spring Batch job through a task, Spring Cloud Task can be configured to\nemit informational messages based on the Spring Batch listeners available in Spring Batch.\nSpecifically, the following Spring Batch listeners are autoconfigured into each batch job\nand emit messages on the associated Spring Cloud Stream channels when run through Spring\nCloud Task:\n\n* `JobExecutionListener` listens for `job-execution-events`\n* `StepExecutionListener` listens for `step-execution-events`\n* `ChunkListener` listens for `chunk-events`\n* `ItemReadListener` listens for `item-read-events`\n* `ItemProcessListener` listens for `item-process-events`\n* `ItemWriteListener` listens for `item-write-events`\n* `SkipListener` listens for `skip-events`\n\nThese listeners are autoconfigured into any `AbstractJob` when the appropriate\nbeans (a `Job` and a `TaskLifecycleListener`) exist in the context. Configuration to\nlisten to these events is handled the same way binding to any other Spring\nCloud Stream channel is done.  Our task (the one running the batch job) serves as a\n`Source`, with the listening applications serving as either a `Processor` or a `Sink`.\n\nAn example could be to have an application listening to the `job-execution-events` channel\nfor the start and stop of a job. To configure the listening application, you would\nconfigure the input to be `job-execution-events` as follows:\n\n`spring.cloud.stream.bindings.input.destination=job-execution-events`\n\nNOTE: A binder implementation is also required to be on the classpath.\n\nNOTE: A sample batch event application can be found in the samples module\nof the Spring Cloud Task Project,\nhttps://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/batch-events[here].\n\n[[sending-batch-events-to-different-channels]]\n=== Sending Batch Events to Different Channels\n\nOne of the options that Spring Cloud Task offers for batch events is the ability to alter\nthe channel to which a specific listener can emit its messages. To do so, use the\nfollowing configuration:\n`spring.cloud.stream.bindings.<the channel>.destination=<new destination>`. For example,\nif `StepExecutionListener` needs to emit its messages to another channel called\n`my-step-execution-events` instead of the default `step-execution-events`, you can add the\nfollowing configuration:\n\n`spring.cloud.task.batch.events.step-execution-events-binding-name=my-step-execution-events`\n\n[[disabling-batch-events]]\n=== Disabling Batch Events\nTo disable the listener functionality for all batch events, use the following\nconfiguration:\n\n`spring.cloud.task.batch.events.enabled=false`\n\nTo disable a specific batch event, use the following configuration:\n\n`spring.cloud.task.batch.events.<batch event listener>.enabled=false`:\n\nThe following listing shows individual listeners that you can disable:\n\n[source,bash]\n----\nspring.cloud.task.batch.events.job-execution.enabled=false\nspring.cloud.task.batch.events.step-execution.enabled=false\nspring.cloud.task.batch.events.chunk.enabled=false\nspring.cloud.task.batch.events.item-read.enabled=false\nspring.cloud.task.batch.events.item-process.enabled=false\nspring.cloud.task.batch.events.item-write.enabled=false\nspring.cloud.task.batch.events.skip.enabled=false\n----\n\n[[emit-order-for-batch-events]]\n=== Emit Order for Batch Events\nBy default, batch events have `Ordered.LOWEST_PRECEDENCE`. To change this value (for\nexample, to 5 ), use the following configuration:\n\n[source,bash]\n----\nspring.cloud.task.batch.events.job-execution-order=5\nspring.cloud.task.batch.events.step-execution-order=5\nspring.cloud.task.batch.events.chunk-order=5\nspring.cloud.task.batch.events.item-read-order=5\nspring.cloud.task.batch.events.item-process-order=5\nspring.cloud.task.batch.events.item-write-order=5\nspring.cloud.task.batch.events.skip-order=5\n----\n"
  },
  {
    "path": "docs/modules/ROOT/partials/_configprops.adoc",
    "content": "|===\n|Name | Default | Description\n\n|spring.cloud.task.batch.application-runner-order | `+++0+++` | The order for the {@code ApplicationRunner} used to run batch jobs when {@code spring.cloud.task.batch.fail-on-job-failure=true}. Defaults to 0 (same as the {@link org.springframework.boot.batch.autoconfigure.JobLauncherApplicationRunner}).\n|spring.cloud.task.batch.command-line-runner-order |  | \n|spring.cloud.task.batch.events.chunk-event-binding-name | `+++chunk-events+++` | \n|spring.cloud.task.batch.events.chunk-order |  | Establishes the default {@link Ordered} precedence for {@link org.springframework.batch.core.ChunkListener}.\n|spring.cloud.task.batch.events.chunk.enabled | `+++true+++` | This property is used to determine if a task should listen for batch chunk events.\n|spring.cloud.task.batch.events.enabled | `+++true+++` | This property is used to determine if a task should listen for batch events.\n|spring.cloud.task.batch.events.item-process-event-binding-name | `+++item-process-events+++` | \n|spring.cloud.task.batch.events.item-process-order |  | Establishes the default {@link Ordered} precedence for {@link org.springframework.batch.core.ItemProcessListener}.\n|spring.cloud.task.batch.events.item-process.enabled | `+++true+++` | This property is used to determine if a task should listen for batch item processed events.\n|spring.cloud.task.batch.events.item-read-event-binding-name | `+++item-read-events+++` | \n|spring.cloud.task.batch.events.item-read-order |  | Establishes the default {@link Ordered} precedence for {@link org.springframework.batch.core.ItemReadListener}.\n|spring.cloud.task.batch.events.item-read.enabled | `+++true+++` | This property is used to determine if a task should listen for batch item read events.\n|spring.cloud.task.batch.events.item-write-event-binding-name | `+++item-write-events+++` | \n|spring.cloud.task.batch.events.item-write-order |  | Establishes the default {@link Ordered} precedence for {@link org.springframework.batch.core.ItemWriteListener}.\n|spring.cloud.task.batch.events.item-write.enabled | `+++true+++` | This property is used to determine if a task should listen for batch item write events.\n|spring.cloud.task.batch.events.job-execution-event-binding-name | `+++job-execution-events+++` | \n|spring.cloud.task.batch.events.job-execution-order |  | Establishes the default {@link Ordered} precedence for {@link org.springframework.batch.core.JobExecutionListener}.\n|spring.cloud.task.batch.events.job-execution.enabled | `+++true+++` | This property is used to determine if a task should listen for batch job execution events.\n|spring.cloud.task.batch.events.skip-event-binding-name | `+++skip-events+++` | \n|spring.cloud.task.batch.events.skip-order |  | Establishes the default {@link Ordered} precedence for {@link org.springframework.batch.core.SkipListener}.\n|spring.cloud.task.batch.events.skip.enabled | `+++true+++` | This property is used to determine if a task should listen for batch skip events.\n|spring.cloud.task.batch.events.step-execution-event-binding-name | `+++step-execution-events+++` | \n|spring.cloud.task.batch.events.step-execution-order |  | Establishes the default {@link Ordered} precedence for {@link org.springframework.batch.core.StepExecutionListener}.\n|spring.cloud.task.batch.events.step-execution.enabled | `+++true+++` | This property is used to determine if a task should listen for batch step execution events.\n|spring.cloud.task.batch.events.task-event-binding-name | `+++task-events+++` | \n|spring.cloud.task.batch.fail-on-job-failure | `+++false+++` | This property is used to determine if a task app should return with a non zero exit code if a batch job fails.\n|spring.cloud.task.batch.fail-on-job-failure-poll-interval | `+++5000+++` | Fixed delay in milliseconds that Spring Cloud Task will wait when checking if {@link org.springframework.batch.core.JobExecution}s have completed, when spring.cloud.task.batch.failOnJobFailure is set to true. Defaults to 5000.\n|spring.cloud.task.batch.job-names |  | Comma-separated list of job names to execute on startup (for instance, `job1,job2`). By default, all Jobs found in the context are executed. @deprecated use spring.batch.job.name instead of spring.cloud.task.batch.jobNames.\n|spring.cloud.task.batch.listener.enabled | `+++true+++` | This property is used to determine if a task will be linked to the batch jobs that are run.\n|spring.cloud.task.closecontext-enabled | `+++false+++` | When set to true the context is closed at the end of the task. Else the context remains open.\n|spring.cloud.task.events.enabled | `+++true+++` | This property is used to determine if a task app should emit task events.\n|spring.cloud.task.executionid |  | An id that will be used by the task when updating the task execution.\n|spring.cloud.task.external-execution-id |  | An id that can be associated with a task.\n|spring.cloud.task.initialize-enabled |  | If set to true then tables are initialized. If set to false tables are not initialized. Defaults to null. The requirement for it to be defaulted to null is so that we can support the <code>spring.cloud.task.initialize.enable</code> until it is removed.\n|spring.cloud.task.parent-execution-id |  | The id of the parent task execution id that launched this task execution. Defaults to null if task execution had no parent.\n|spring.cloud.task.single-instance-enabled | `+++false+++` | This property is used to determine if a task will execute if another task with the same app name is running.\n|spring.cloud.task.single-instance-lock-check-interval | `+++500+++` | Declares the time (in millis) that a task execution will wait between checks. Default time is: 500 millis.\n|spring.cloud.task.single-instance-lock-ttl |  | Declares the maximum amount of time (in millis) that a task execution can hold a lock to prevent another task from executing with a specific task name when the single-instance-enabled is set to true. Default time is: Integer.MAX_VALUE.\n|spring.cloud.task.table-prefix | `+++TASK_+++` | The prefix to append to the table names created by Spring Cloud Task.\n|spring.cloud.task.transaction-manager | `+++springCloudTaskTransactionManager+++` | This property is used to specify the transaction manager for TaskRepository. By default, a dedicated transaction manager is created by spring.\n\n|==="
  },
  {
    "path": "docs/modules/ROOT/partials/_conventions.adoc",
    "content": "[[observability-conventions]]\n=== Observability - Conventions\n\nBelow you can find a list of all `GlobalObservationConvention` and `ObservationConvention` declared by this project.\n\n.ObservationConvention implementations\n|===\n|ObservationConvention Class Name | Applicable ObservationContext Class Name\n|`org.springframework.cloud.task.listener.DefaultTaskExecutionObservationConvention`|`TaskExecutionObservationContext`\n|`org.springframework.cloud.task.listener.TaskExecutionObservationConvention`|`TaskExecutionObservationContext`\n|`org.springframework.cloud.task.configuration.observation.DefaultTaskObservationConvention`|`TaskObservationContext`\n|`org.springframework.cloud.task.configuration.observation.TaskObservationConvention`|`TaskObservationContext`\n|===\n"
  },
  {
    "path": "docs/modules/ROOT/partials/_metrics.adoc",
    "content": "[[observability-metrics]]\n=== Observability - Metrics\n\nBelow you can find a list of all metrics declared by this project.\n\n[[observability-metrics-task-active]]\n==== Task Active\n\n____\nMetrics created around a task execution.\n____\n\n\n**Metric name** `spring.cloud.task` (defined by convention class `org.springframework.cloud.task.listener.DefaultTaskExecutionObservationConvention`). **Type** `timer`.\n\n**Metric name** `spring.cloud.task.active` (defined by convention class `org.springframework.cloud.task.listener.DefaultTaskExecutionObservationConvention`). **Type** `long task timer`.\n\n\nIMPORTANT: KeyValues that are added after starting the Observation might be missing from the *.active metrics.\n\n\nIMPORTANT: Micrometer internally uses `nanoseconds` for the baseunit. However, each backend determines the actual baseunit. (i.e. Prometheus uses seconds)\n\n\nFully qualified name of the enclosing class `org.springframework.cloud.task.listener.TaskExecutionObservation`.\n\nIMPORTANT: All tags must be prefixed with `spring.cloud.task` prefix!\n\n.Low cardinality Keys\n[cols=\"a,a\"]\n|===\n|Name | Description\n|`spring.cloud.task.cf.app.id` _(required)_|App id for CF cloud.\n|`spring.cloud.task.cf.app.name` _(required)_|App name for CF cloud.\n|`spring.cloud.task.cf.app.version` _(required)_|App version for CF cloud.\n|`spring.cloud.task.cf.instance.index` _(required)_|Instance index for CF cloud.\n|`spring.cloud.task.cf.org.name` _(required)_|Organization Name for CF cloud.\n|`spring.cloud.task.cf.space.id` _(required)_|Space id for CF cloud.\n|`spring.cloud.task.cf.space.name` _(required)_|Space name for CF cloud.\n|`spring.cloud.task.execution.id` _(required)_|Task execution id.\n|`spring.cloud.task.exit.code` _(required)_|Task exit code.\n|`spring.cloud.task.external.execution.id` _(required)_|External execution id for task.\n|`spring.cloud.task.name` _(required)_|Task name measurement.\n|`spring.cloud.task.parent.execution.id` _(required)_|Task parent execution id.\n|`spring.cloud.task.status` _(required)_|task status. Can be either success or failure.\n|===\n\n\n\n[[observability-metrics-task-runner-observation]]\n==== Task Runner Observation\n\n____\nObservation created when a task runner is executed.\n____\n\n\n**Metric name** `spring.cloud.task.runner` (defined by convention class `org.springframework.cloud.task.configuration.observation.DefaultTaskObservationConvention`). **Type** `timer`.\n\n**Metric name** `spring.cloud.task.runner.active` (defined by convention class `org.springframework.cloud.task.configuration.observation.DefaultTaskObservationConvention`). **Type** `long task timer`.\n\n\nIMPORTANT: KeyValues that are added after starting the Observation might be missing from the *.active metrics.\n\n\nIMPORTANT: Micrometer internally uses `nanoseconds` for the baseunit. However, each backend determines the actual baseunit. (i.e. Prometheus uses seconds)\n\n\nFully qualified name of the enclosing class `org.springframework.cloud.task.configuration.observation.TaskDocumentedObservation`.\n\nIMPORTANT: All tags must be prefixed with `spring.cloud.task` prefix!\n\n.Low cardinality Keys\n[cols=\"a,a\"]\n|===\n|Name | Description\n|`spring.cloud.task.runner.bean-name` _(required)_|Name of the bean that was executed by Spring Cloud Task.\n|===\n\n\n\n\n"
  },
  {
    "path": "docs/modules/ROOT/partials/_spans.adoc",
    "content": "[[observability-spans]]\n=== Observability - Spans\n\nBelow you can find a list of all spans declared by this project.\n\n[[observability-spans-task-active]]\n==== Task Active Span\n\n> Metrics created around a task execution.\n\n**Span name** `spring.cloud.task` (defined by convention class `org.springframework.cloud.task.listener.DefaultTaskExecutionObservationConvention`).\n\nFully qualified name of the enclosing class `org.springframework.cloud.task.listener.TaskExecutionObservation`.\n\nIMPORTANT: All tags must be prefixed with `spring.cloud.task` prefix!\n\n.Tag Keys\n|===\n|Name | Description\n|`spring.cloud.task.cf.app.id` _(required)_|App id for CF cloud.\n|`spring.cloud.task.cf.app.name` _(required)_|App name for CF cloud.\n|`spring.cloud.task.cf.app.version` _(required)_|App version for CF cloud.\n|`spring.cloud.task.cf.instance.index` _(required)_|Instance index for CF cloud.\n|`spring.cloud.task.cf.org.name` _(required)_|Organization Name for CF cloud.\n|`spring.cloud.task.cf.space.id` _(required)_|Space id for CF cloud.\n|`spring.cloud.task.cf.space.name` _(required)_|Space name for CF cloud.\n|`spring.cloud.task.execution.id` _(required)_|Task execution id.\n|`spring.cloud.task.exit.code` _(required)_|Task exit code.\n|`spring.cloud.task.external.execution.id` _(required)_|External execution id for task.\n|`spring.cloud.task.name` _(required)_|Task name measurement.\n|`spring.cloud.task.parent.execution.id` _(required)_|Task parent execution id.\n|`spring.cloud.task.status` _(required)_|task status. Can be either success or failure.\n|===\n\n\n\n[[observability-spans-task-runner-observation]]\n==== Task Runner Observation Span\n\n> Observation created when a task runner is executed.\n\n**Span name** `spring.cloud.task.runner` (defined by convention class `org.springframework.cloud.task.configuration.observation.DefaultTaskObservationConvention`).\n\nFully qualified name of the enclosing class `org.springframework.cloud.task.configuration.observation.TaskDocumentedObservation`.\n\nIMPORTANT: All tags must be prefixed with `spring.cloud.task` prefix!\n\n.Tag Keys\n|===\n|Name | Description\n|`spring.cloud.task.runner.bean-name` _(required)_|Name of the bean that was executed by Spring Cloud Task.\n|===\n\n\n\n\n"
  },
  {
    "path": "docs/package.json",
    "content": "{\n\t\"dependencies\": {\n\t\t\"antora\": \"3.2.0-alpha.9\",\n\t\t\"@antora/atlas-extension\": \"1.0.0-alpha.5\",\n\t\t\"@antora/collector-extension\": \"1.0.2\",\n\t\t\"@asciidoctor/tabs\": \"1.0.0-beta.6\",\n\t\t\"@springio/antora-extensions\": \"1.14.7\",\n\t\t\"@springio/asciidoctor-extensions\": \"1.0.0-alpha.17\"\n\t}\n}\n"
  },
  {
    "path": "docs/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>org.springframework.cloud</groupId>\n\t<artifactId>spring-cloud-task-docs</artifactId>\n\t<parent>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<artifactId>spring-cloud-task-parent</artifactId>\n\t\t<version>5.0.2-SNAPSHOT</version>\n\t</parent>\n\t<packaging>jar</packaging>\n\t<name>Spring Cloud Task Docs</name>\n\t<description>Spring Cloud Task Docs</description>\n\t<properties>\n\t\t<docs.main>spring-cloud-task</docs.main>\n\t\t<main.basedir>${basedir}/..</main.basedir>\n\t\t<configprops.inclusionPattern>spring.cloud.*</configprops.inclusionPattern>\n\t\t<!-- Don't upload docs jar to central / repo.spring.io -->\n\t\t<maven-deploy-plugin-default.phase>none</maven-deploy-plugin-default.phase>\n\n\t\t<!-- Observability -->\n\t\t<micrometer-docs-generator.version>1.0.2</micrometer-docs-generator.version>\n\t\t<micrometer-docs-generator.inputPath>${maven.multiModuleProjectDirectory}/spring-cloud-task-core/</micrometer-docs-generator.inputPath>\n\t\t<micrometer-docs-generator.inclusionPattern>.*</micrometer-docs-generator.inclusionPattern>\n\t\t<micrometer-docs-generator.outputPath>${maven.multiModuleProjectDirectory}/docs/modules/ROOT/partials/</micrometer-docs-generator.outputPath>\n\t</properties>\n\t<build>\n\t\t<sourceDirectory>src/main/asciidoc</sourceDirectory>\n\t</build>\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>enable-configuration-properties</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>!disableConfigurationProperties</name>\n\t\t\t\t</property>\n\t\t\t</activation>\n\t\t\t<dependencies>\n\t\t\t\t<dependency>\n\t\t\t\t\t<groupId>${project.groupId}</groupId>\n\t\t\t\t\t<artifactId>spring-cloud-starter-single-step-batch-job</artifactId>\n\t\t\t\t\t<version>${project.version}</version>\n\t\t\t\t</dependency>\n\t\t\t\t<dependency>\n\t\t\t\t\t<groupId>${project.groupId}</groupId>\n\t\t\t\t\t<artifactId>spring-cloud-starter-task</artifactId>\n\t\t\t\t\t<version>${project.version}</version>\n\t\t\t\t</dependency>\n\t\t\t</dependencies>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>docs</id>\n\t\t\t<build>\n\t\t\t\t<resources>\n\t\t\t\t\t<resource>\n\t\t\t\t\t\t<directory>src/main/antora/resources/antora-resources</directory>\n\t\t\t\t\t\t<filtering>true</filtering>\n\t\t\t\t\t</resource>\n\t\t\t\t</resources>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>pl.project13.maven</groupId>\n\t\t\t\t\t\t<artifactId>git-commit-id-plugin</artifactId>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-dependency-plugin</artifactId>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t\t\t<artifactId>exec-maven-plugin</artifactId>\n\t\t\t\t\t\t<!-- TODO: Remove this execution if you have no observability -->\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>generate-observability-docs</id>\n\t\t\t\t\t\t\t\t<phase>${generate-docs.phase}</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>java</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t\t\t<mainClass>io.micrometer.docs.DocsGeneratorCommand</mainClass>\n\t\t\t\t\t\t\t\t\t<includePluginDependencies>true</includePluginDependencies>\n\t\t\t\t\t\t\t\t\t<arguments>\n\t\t\t\t\t\t\t\t\t\t<argument>${micrometer-docs-generator.inputPath}</argument>\n\t\t\t\t\t\t\t\t\t\t<argument>${micrometer-docs-generator.inclusionPattern}</argument>\n\t\t\t\t\t\t\t\t\t\t<argument>${micrometer-docs-generator.outputPath}</argument>\n\t\t\t\t\t\t\t\t\t</arguments>\n\t\t\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t\t<dependencies>\n\t\t\t\t\t\t\t<dependency>\n\t\t\t\t\t\t\t\t<groupId>io.micrometer</groupId>\n\t\t\t\t\t\t\t\t<artifactId>micrometer-docs-generator</artifactId>\n\t\t\t\t\t\t\t\t<version>${micrometer-docs-generator.version}</version>\n\t\t\t\t\t\t\t\t<type>jar</type>\n\t\t\t\t\t\t\t</dependency>\n\t\t\t\t\t\t</dependencies>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>io.spring.maven.antora</groupId>\n\t\t\t\t\t\t<artifactId>antora-component-version-maven-plugin</artifactId>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.antora</groupId>\n\t\t\t\t\t\t<artifactId>antora-maven-plugin</artifactId>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-antrun-plugin</artifactId>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>copying-javadocs</id>\n\t\t\t\t\t\t\t\t<phase>prepare-package</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>run</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t\t\t<target>\n\t\t\t\t\t\t\t\t\t\t<mkdir dir=\"${project.basedir}/target/generated-docs/apidocs\"/>\n\t\t\t\t\t\t\t\t\t</target>\n\t\t\t\t\t\t\t\t\t<target>\n\t\t\t\t\t\t\t\t\t\t<copy todir=\"${project.basedir}/target/generated-docs/apidocs\">\n\t\t\t\t\t\t\t\t\t\t\t<fileset dir=\"${maven.multiModuleProjectDirectory}/target/reports/apidocs\"/>\n\t\t\t\t\t\t\t\t\t\t</copy>\n\t\t\t\t\t\t\t\t\t</target>\n\t\t\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "docs/src/main/antora/resources/antora-resources/antora.yml",
    "content": "version: @antora-component.version@\nprerelease: @antora-component.prerelease@\n\nasciidoc:\n  attributes:\n    attribute-missing: 'warn'\n    chomp: 'all'\n    project-root: @maven.multiModuleProjectDirectory@\n    github-repo: @docs.main@\n    github-raw: https://raw.githubusercontent.com/spring-cloud/@docs.main@/@github-tag@\n    github-code: https://github.com/spring-cloud/@docs.main@/tree/@github-tag@\n    github-issues: https://github.com/spring-cloud/@docs.main@/issues/\n    github-wiki: https://github.com/spring-cloud/@docs.main@/wiki\n    spring-cloud-version: @project.version@\n    github-tag: @github-tag@\n    version-type: @version-type@\n    docs-url: https://docs.spring.io/@docs.main@/docs/@project.version@\n    raw-docs-url: https://raw.githubusercontent.com/spring-cloud/@docs.main@/@github-tag@\n    project-version: @project.version@\n    project-name: @docs.main@\n"
  },
  {
    "path": "docs/src/main/asciidoc/.gitignore",
    "content": "*.html\n*.css\n"
  },
  {
    "path": "docs/src/main/asciidoc/Guardfile",
    "content": "require 'asciidoctor'\nrequire 'erb'\n\nguard 'shell' do\n\twatch(/.*\\.adoc$/) {|m|\n\t\tAsciidoctor.render_file('index.adoc', \\\n\t\t\t  :in_place => true, \\\n\t\t\t  :safe => Asciidoctor::SafeMode::UNSAFE, \\\n\t\t\t  :attributes => {\\\n\t\t\t\t  'source-highlighter' => 'prettify', \\\n\t\t\t\t  'icons' => 'font', \\\n\t\t\t\t  'linkcss' => 'true', \\\n\t\t\t\t  'copycss' => 'true', \\\n\t\t\t\t  'doctype' => 'book'})\n\t}\nend\n\nguard 'livereload' do\n\twatch(%r{^.+\\.(css|js|html)$})\nend\n"
  },
  {
    "path": "docs/src/main/asciidoc/README.adoc",
    "content": "[[spring-cloud-task]]\n= Spring Cloud Task\n\nIs a project centered around the idea of processing on demand.  A user is able to develop\na “task” that can be deployed, executed and removed on demand, yet the result of the\nprocess persists beyond the life of the task for future reporting.\n\n\n[[requirements:]]\n== Requirements:\n\n* Java 17 or Above\n\n[[build-main-project:]]\n== Build Main Project:\n\n[source,shell,indent=2]\n----\n$ ./mvnw clean install\n----\n\n[[example:]]\n== Example:\n\n[source,java,indent=2]\n----\n@SpringBootApplication\n@EnableTask\npublic class MyApp {\n\n\t@Bean\n\tpublic MyTaskApplication myTask() {\n\t\treturn new MyTaskApplication();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MyApp.class);\n\t}\n\n\tpublic static class MyTaskApplication implements ApplicationRunner {\n\n\t\t@Override\n\t\tpublic void run(ApplicationArguments args) throws Exception {\n\t\t\tSystem.out.println(\"Hello World\");\n\t\t}\n\t}\n}\n----\n\n[[code-of-conduct]]\n== Code of Conduct\nThis project adheres to the Contributor Covenant link:CODE_OF_CONDUCT.adoc[code of conduct]. By participating, you  are expected to uphold this code. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.\n\n[[building-the-project]]\n== Building the Project\n\nThis project requires that you invoke the Javadoc engine from the Maven command line. You can do so by appending `javadoc:aggregate` to the rest of your Maven command.\nFor example, to build the entire project, you could use `mvn clean install -DskipTests -P docs`.\n"
  },
  {
    "path": "docs/src/main/asciidoc/index.htmladoc",
    "content": "include::spring-cloud-task.adoc[]\n"
  },
  {
    "path": "docs/src/main/asciidoc/index.htmlsingleadoc",
    "content": "= Spring Cloud Task Reference Guide\nMichael Minella, Glenn Renfro, Jay Bryant\n\ninclude::_attributes.adoc[]\n\n// ======================================================================================\n\n(C) 2009-2020 VMware, Inc. All rights reserved.\n\nCopies of this document may be made for your own use and for distribution to\nothers, provided that you do not charge any fee for such copies and further\nprovided that each copy contains this Copyright Notice, whether distributed in\nprint or electronically.\n\ninclude::preface.adoc[leveloffset=+1]\n\ninclude::getting-started.adoc[leveloffset=+1]\n\ninclude::features.adoc[leveloffset=+1]\n\ninclude::batch.adoc[leveloffset=+1]\n\ninclude::batch-starter.adoc[leveloffset=+1]\n\ninclude::stream.adoc[leveloffset=+1]\n\ninclude::appendix.adoc[leveloffset=+1]\n\n// ======================================================================================\n"
  },
  {
    "path": "docs/src/main/asciidoc/index.pdfadoc",
    "content": "include::spring-cloud-task.pdfadoc[]\n"
  },
  {
    "path": "docs/src/main/asciidoc/sagan-index.adoc",
    "content": "Spring Cloud Task allows a user to develop and run short lived microservices using Spring Cloud and run them locally, in the cloud, even on Spring Cloud Data Flow. Just add `@EnableTask` and run your app as a Spring Boot app (single application context).\nIf you are new to Spring Cloud Task, take a look at our https://docs.spring.io/spring-cloud-task/docs/2.0.0.RELEASE/reference/htmlsingle/#getting-started[Getting Started] docs.  \n"
  },
  {
    "path": "docs/src/main/asciidoc/spring-cloud-task.epubadoc",
    "content": "= Spring Cloud Task Reference Guide\nMichael Minella, Glenn Renfro, Jay Bryant\n\ninclude::_attributes.adoc[]\n\n// ======================================================================================\n\n(C) 2009-2022 VMware, Inc. All rights reserved.\n\nCopies of this document may be made for your own use and for distribution to\nothers, provided that you do not charge any fee for such copies and further\nprovided that each copy contains this Copyright Notice, whether distributed in\nprint or electronically.\n\ninclude::preface.adoc[leveloffset=+1]\n\ninclude::getting-started.adoc[leveloffset=+1]\n\ninclude::features.adoc[leveloffset=+1]\n\ninclude::batch.adoc[leveloffset=+1]\n\ninclude::batch-starter.adoc[leveloffset=+1]\n\ninclude::stream.adoc[leveloffset=+1]\n\ninclude::appendix.adoc[leveloffset=+1]\n\n// ======================================================================================\n"
  },
  {
    "path": "docs/src/main/asciidoc/spring-cloud-task.htmlsingleadoc",
    "content": "= Spring Cloud Task Reference Guide\nMichael Minella, Glenn Renfro, Jay Bryant\n\ninclude::_attributes.adoc[]\n\n// ======================================================================================\n\n(C) 2009-2020 VMware, Inc. All rights reserved.\n\nCopies of this document may be made for your own use and for distribution to\nothers, provided that you do not charge any fee for such copies and further\nprovided that each copy contains this Copyright Notice, whether distributed in\nprint or electronically.\n\ninclude::preface.adoc[leveloffset=+1]\n\ninclude::getting-started.adoc[leveloffset=+1]\n\ninclude::features.adoc[leveloffset=+1]\n\ninclude::batch.adoc[leveloffset=+1]\n\ninclude::batch-starter.adoc[leveloffset=+1]\n\ninclude::stream.adoc[leveloffset=+1]\n\ninclude::appendix.adoc[leveloffset=+1]\n\n// ======================================================================================\n"
  },
  {
    "path": "docs/src/main/asciidoc/spring-cloud-task.pdfadoc",
    "content": "= Spring Cloud Task Reference Guide\nMichael Minella, Glenn Renfro, Jay Bryant\n\ninclude::_attributes.adoc[]\n\n// ======================================================================================\n\n(C) 2009-2022 VMware, Inc. All rights reserved.\n\nCopies of this document may be made for your own use and for distribution to\nothers, provided that you do not charge any fee for such copies and further\nprovided that each copy contains this Copyright Notice, whether distributed in\nprint or electronically.\n\ninclude::preface.adoc[leveloffset=+1]\n\ninclude::getting-started.adoc[leveloffset=+1]\n\ninclude::features.adoc[leveloffset=+1]\n\ninclude::batch.adoc[leveloffset=+1]\n\ninclude::batch-starter.adoc[leveloffset=+1]\n\ninclude::stream.adoc[leveloffset=+1]\n\ninclude::appendix.adoc[leveloffset=+1]\n\n// ======================================================================================\n"
  },
  {
    "path": "docs/src/main/javadoc/spring-javadoc.css",
    "content": "/* Javadoc style sheet */\n/*\nOverall document style\n*/\n@import url('resources/fonts/dejavu.css');\n\nbody {\n\tbackground-color: #ffffff;\n\tcolor: #353833;\n\tfont-family: 'DejaVu Sans', Arial, Helvetica, sans-serif;\n\tfont-size: 14px;\n\tmargin: 0;\n}\n\na:link, a:visited {\n\ttext-decoration: none;\n\tcolor: #4A6782;\n}\n\na:hover, a:focus {\n\ttext-decoration: none;\n\tcolor: #bb7a2a;\n}\n\na:active {\n\ttext-decoration: none;\n\tcolor: #4A6782;\n}\n\na[name] {\n\tcolor: #353833;\n}\n\na[name]:hover {\n\ttext-decoration: none;\n\tcolor: #353833;\n}\n\npre {\n\tfont-family: 'DejaVu Sans Mono', monospace;\n\tfont-size: 14px;\n}\n\nh1 {\n\tfont-size: 20px;\n}\n\nh2 {\n\tfont-size: 18px;\n}\n\nh3 {\n\tfont-size: 16px;\n\tfont-style: italic;\n}\n\nh4 {\n\tfont-size: 13px;\n}\n\nh5 {\n\tfont-size: 12px;\n}\n\nh6 {\n\tfont-size: 11px;\n}\n\nul {\n\tlist-style-type: disc;\n}\n\ncode, tt {\n\tfont-family: 'DejaVu Sans Mono', monospace;\n\tfont-size: 14px;\n\tpadding-top: 4px;\n\tmargin-top: 8px;\n\tline-height: 1.4em;\n}\n\ndt code {\n\tfont-family: 'DejaVu Sans Mono', monospace;\n\tfont-size: 14px;\n\tpadding-top: 4px;\n}\n\ntable tr td dt code {\n\tfont-family: 'DejaVu Sans Mono', monospace;\n\tfont-size: 14px;\n\tvertical-align: top;\n\tpadding-top: 4px;\n}\n\nsup {\n\tfont-size: 8px;\n}\n\n/*\nDocument title and Copyright styles\n*/\n.clear {\n\tclear: both;\n\theight: 0px;\n\toverflow: hidden;\n}\n\n.aboutLanguage {\n\tfloat: right;\n\tpadding: 0px 21px;\n\tfont-size: 11px;\n\tz-index: 200;\n\tmargin-top: -9px;\n}\n\n.legalCopy {\n\tmargin-left: .5em;\n}\n\n.bar a, .bar a:link, .bar a:visited, .bar a:active {\n\tcolor: #FFFFFF;\n\ttext-decoration: none;\n}\n\n.bar a:hover, .bar a:focus {\n\tcolor: #bb7a2a;\n}\n\n.tab {\n\tbackground-color: #0066FF;\n\tcolor: #ffffff;\n\tpadding: 8px;\n\twidth: 5em;\n\tfont-weight: bold;\n}\n\n/*\nNavigation bar styles\n*/\n.bar {\n\tbackground-color: #4D7A97;\n\tcolor: #FFFFFF;\n\tpadding: .8em .5em .4em .8em;\n\theight: auto; /*height:1.8em;*/\n\tfont-size: 11px;\n\tmargin: 0;\n}\n\n.topNav {\n\tbackground-color: #4D7A97;\n\tcolor: #FFFFFF;\n\tfloat: left;\n\tpadding: 0;\n\twidth: 100%;\n\tclear: right;\n\theight: 2.8em;\n\tpadding-top: 10px;\n\toverflow: hidden;\n\tfont-size: 12px;\n}\n\n.bottomNav {\n\tmargin-top: 10px;\n\tbackground-color: #4D7A97;\n\tcolor: #FFFFFF;\n\tfloat: left;\n\tpadding: 0;\n\twidth: 100%;\n\tclear: right;\n\theight: 2.8em;\n\tpadding-top: 10px;\n\toverflow: hidden;\n\tfont-size: 12px;\n}\n\n.subNav {\n\tbackground-color: #dee3e9;\n\tfloat: left;\n\twidth: 100%;\n\toverflow: hidden;\n\tfont-size: 12px;\n}\n\n.subNav div {\n\tclear: left;\n\tfloat: left;\n\tpadding: 0 0 5px 6px;\n\ttext-transform: uppercase;\n}\n\nul.navList, ul.subNavList {\n\tfloat: left;\n\tmargin: 0 25px 0 0;\n\tpadding: 0;\n}\n\nul.navList li {\n\tlist-style: none;\n\tfloat: left;\n\tpadding: 5px 6px;\n\ttext-transform: uppercase;\n}\n\nul.subNavList li {\n\tlist-style: none;\n\tfloat: left;\n}\n\n.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited {\n\tcolor: #FFFFFF;\n\ttext-decoration: none;\n\ttext-transform: uppercase;\n}\n\n.topNav a:hover, .bottomNav a:hover {\n\ttext-decoration: none;\n\tcolor: #bb7a2a;\n\ttext-transform: uppercase;\n}\n\n.navBarCell1Rev {\n\tbackground-color: #F8981D;\n\tcolor: #253441;\n\tmargin: auto 5px;\n}\n\n.skipNav {\n\tposition: absolute;\n\ttop: auto;\n\tleft: -9999px;\n\toverflow: hidden;\n}\n\n/*\nPage header and footer styles\n*/\n.header, .footer {\n\tclear: both;\n\tmargin: 0 20px;\n\tpadding: 5px 0 0 0;\n}\n\n.indexHeader {\n\tmargin: 10px;\n\tposition: relative;\n}\n\n.indexHeader span {\n\tmargin-right: 15px;\n}\n\n.indexHeader h1 {\n\tfont-size: 13px;\n}\n\n.title {\n\tcolor: #2c4557;\n\tmargin: 10px 0;\n}\n\n.subTitle {\n\tmargin: 5px 0 0 0;\n}\n\n.header ul {\n\tmargin: 0 0 15px 0;\n\tpadding: 0;\n}\n\n.footer ul {\n\tmargin: 20px 0 5px 0;\n}\n\n.header ul li, .footer ul li {\n\tlist-style: none;\n\tfont-size: 13px;\n}\n\n/*\nHeading styles\n*/\ndiv.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 {\n\tbackground-color: #dee3e9;\n\tborder: 1px solid #d0d9e0;\n\tmargin: 0 0 6px -8px;\n\tpadding: 7px 5px;\n}\n\nul.blockList ul.blockList ul.blockList li.blockList h3 {\n\tbackground-color: #dee3e9;\n\tborder: 1px solid #d0d9e0;\n\tmargin: 0 0 6px -8px;\n\tpadding: 7px 5px;\n}\n\nul.blockList ul.blockList li.blockList h3 {\n\tpadding: 0;\n\tmargin: 15px 0;\n}\n\nul.blockList li.blockList h2 {\n\tpadding: 0px 0 20px 0;\n}\n\n/*\nPage layout container styles\n*/\n.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer {\n\tclear: both;\n\tpadding: 10px 20px;\n\tposition: relative;\n}\n\n.indexContainer {\n\tmargin: 10px;\n\tposition: relative;\n\tfont-size: 12px;\n}\n\n.indexContainer h2 {\n\tfont-size: 13px;\n\tpadding: 0 0 3px 0;\n}\n\n.indexContainer ul {\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.indexContainer ul li {\n\tlist-style: none;\n\tpadding-top: 2px;\n}\n\n.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt {\n\tfont-size: 12px;\n\tfont-weight: bold;\n\tmargin: 10px 0 0 0;\n\tcolor: #4E4E4E;\n}\n\n.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd {\n\tmargin: 5px 0 10px 0px;\n\tfont-size: 14px;\n\tfont-family: 'DejaVu Sans Mono', monospace;\n}\n\n.serializedFormContainer dl.nameValue dt {\n\tmargin-left: 1px;\n\tfont-size: 1.1em;\n\tdisplay: inline;\n\tfont-weight: bold;\n}\n\n.serializedFormContainer dl.nameValue dd {\n\tmargin: 0 0 0 1px;\n\tfont-size: 1.1em;\n\tdisplay: inline;\n}\n\n/*\nList styles\n*/\nul.horizontal li {\n\tdisplay: inline;\n\tfont-size: 0.9em;\n}\n\nul.inheritance {\n\tmargin: 0;\n\tpadding: 0;\n}\n\nul.inheritance li {\n\tdisplay: inline;\n\tlist-style: none;\n}\n\nul.inheritance li ul.inheritance {\n\tmargin-left: 15px;\n\tpadding-left: 15px;\n\tpadding-top: 1px;\n}\n\nul.blockList, ul.blockListLast {\n\tmargin: 10px 0 10px 0;\n\tpadding: 0;\n}\n\nul.blockList li.blockList, ul.blockListLast li.blockList {\n\tlist-style: none;\n\tmargin-bottom: 15px;\n\tline-height: 1.4;\n}\n\nul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList {\n\tpadding: 0px 20px 5px 10px;\n\tborder: 1px solid #ededed;\n\tbackground-color: #f8f8f8;\n}\n\nul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList {\n\tpadding: 0 0 5px 8px;\n\tbackground-color: #ffffff;\n\tborder: none;\n}\n\nul.blockList ul.blockList ul.blockList ul.blockList li.blockList {\n\tmargin-left: 0;\n\tpadding-left: 0;\n\tpadding-bottom: 15px;\n\tborder: none;\n}\n\nul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast {\n\tlist-style: none;\n\tborder-bottom: none;\n\tpadding-bottom: 0;\n}\n\ntable tr td dl, table tr td dl dt, table tr td dl dd {\n\tmargin-top: 0;\n\tmargin-bottom: 1px;\n}\n\n/*\nTable styles\n*/\n.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary {\n\twidth: 100%;\n\tborder-left: 1px solid #EEE;\n\tborder-right: 1px solid #EEE;\n\tborder-bottom: 1px solid #EEE;\n}\n\n.overviewSummary, .memberSummary {\n\tpadding: 0px;\n}\n\n.overviewSummary caption, .memberSummary caption, .typeSummary caption,\n.useSummary caption, .constantsSummary caption, .deprecatedSummary caption {\n\tposition: relative;\n\ttext-align: left;\n\tbackground-repeat: no-repeat;\n\tcolor: #253441;\n\tfont-weight: bold;\n\tclear: none;\n\toverflow: hidden;\n\tpadding: 0px;\n\tpadding-top: 10px;\n\tpadding-left: 1px;\n\tmargin: 0px;\n\twhite-space: pre;\n}\n\n.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link,\n.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link,\n.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover,\n.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover,\n.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active,\n.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active,\n.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited,\n.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited {\n\tcolor: #FFFFFF;\n}\n\n.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span,\n.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span {\n\twhite-space: nowrap;\n\tpadding-top: 5px;\n\tpadding-left: 12px;\n\tpadding-right: 12px;\n\tpadding-bottom: 7px;\n\tdisplay: inline-block;\n\tfloat: left;\n\tbackground-color: #F8981D;\n\tborder: none;\n\theight: 16px;\n}\n\n.memberSummary caption span.activeTableTab span {\n\twhite-space: nowrap;\n\tpadding-top: 5px;\n\tpadding-left: 12px;\n\tpadding-right: 12px;\n\tmargin-right: 3px;\n\tdisplay: inline-block;\n\tfloat: left;\n\tbackground-color: #F8981D;\n\theight: 16px;\n}\n\n.memberSummary caption span.tableTab span {\n\twhite-space: nowrap;\n\tpadding-top: 5px;\n\tpadding-left: 12px;\n\tpadding-right: 12px;\n\tmargin-right: 3px;\n\tdisplay: inline-block;\n\tfloat: left;\n\tbackground-color: #4D7A97;\n\theight: 16px;\n}\n\n.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab {\n\tpadding-top: 0px;\n\tpadding-left: 0px;\n\tpadding-right: 0px;\n\tbackground-image: none;\n\tfloat: none;\n\tdisplay: inline;\n}\n\n.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd,\n.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd {\n\tdisplay: none;\n\twidth: 5px;\n\tposition: relative;\n\tfloat: left;\n\tbackground-color: #F8981D;\n}\n\n.memberSummary .activeTableTab .tabEnd {\n\tdisplay: none;\n\twidth: 5px;\n\tmargin-right: 3px;\n\tposition: relative;\n\tfloat: left;\n\tbackground-color: #F8981D;\n}\n\n.memberSummary .tableTab .tabEnd {\n\tdisplay: none;\n\twidth: 5px;\n\tmargin-right: 3px;\n\tposition: relative;\n\tbackground-color: #4D7A97;\n\tfloat: left;\n\n}\n\n.overviewSummary td, .memberSummary td, .typeSummary td,\n.useSummary td, .constantsSummary td, .deprecatedSummary td {\n\ttext-align: left;\n\tpadding: 0px 0px 12px 10px;\n\twidth: 100%;\n}\n\nth.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th,\ntd.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td {\n\tvertical-align: top;\n\tpadding-right: 0px;\n\tpadding-top: 8px;\n\tpadding-bottom: 3px;\n}\n\nth.colFirst, th.colLast, th.colOne, .constantsSummary th {\n\tbackground: #dee3e9;\n\ttext-align: left;\n\tpadding: 8px 3px 3px 7px;\n}\n\ntd.colFirst, th.colFirst {\n\twhite-space: nowrap;\n\tfont-size: 13px;\n}\n\ntd.colLast, th.colLast {\n\tfont-size: 13px;\n}\n\ntd.colOne, th.colOne {\n\tfont-size: 13px;\n}\n\n.overviewSummary td.colFirst, .overviewSummary th.colFirst,\n.overviewSummary td.colOne, .overviewSummary th.colOne,\n.memberSummary td.colFirst, .memberSummary th.colFirst,\n.memberSummary td.colOne, .memberSummary th.colOne,\n.typeSummary td.colFirst {\n\twidth: 25%;\n\tvertical-align: top;\n}\n\ntd.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover {\n\tfont-weight: bold;\n}\n\n.tableSubHeadingColor {\n\tbackground-color: #EEEEFF;\n}\n\n.altColor {\n\tbackground-color: #FFFFFF;\n}\n\n.rowColor {\n\tbackground-color: #EEEEEF;\n}\n\n/*\nContent styles\n*/\n.description pre {\n\tmargin-top: 0;\n}\n\n.deprecatedContent {\n\tmargin: 0;\n\tpadding: 10px 0;\n}\n\n.docSummary {\n\tpadding: 0;\n}\n\nul.blockList ul.blockList ul.blockList li.blockList h3 {\n\tfont-style: normal;\n}\n\ndiv.block {\n\tfont-size: 14px;\n\tfont-family: 'DejaVu Serif', Georgia, \"Times New Roman\", Times, serif;\n}\n\ntd.colLast div {\n\tpadding-top: 0px;\n}\n\n\ntd.colLast a {\n\tpadding-bottom: 3px;\n}\n\n/*\nFormatting effect styles\n*/\n.sourceLineNo {\n\tcolor: green;\n\tpadding: 0 30px 0 0;\n}\n\nh1.hidden {\n\tvisibility: hidden;\n\toverflow: hidden;\n\tfont-size: 10px;\n}\n\n.block {\n\tdisplay: block;\n\tmargin: 3px 10px 2px 0px;\n\tcolor: #474747;\n}\n\n.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink,\n.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel,\n.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink {\n\tfont-weight: bold;\n}\n\n.deprecationComment, .emphasizedPhrase, .interfaceName {\n\tfont-style: italic;\n}\n\ndiv.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase,\ndiv.block div.block span.interfaceName {\n\tfont-style: normal;\n}\n\ndiv.contentContainer ul.blockList li.blockList h2 {\n\tpadding-bottom: 0px;\n}\n\n\n/*\nSpring\n*/\n\npre.code {\n\tbackground-color: #F8F8F8;\n\tborder: 1px solid #CCCCCC;\n\tborder-radius: 3px 3px 3px 3px;\n\toverflow: auto;\n\tpadding: 10px;\n\tmargin: 4px 20px 2px 0px;\n}\n\npre.code code, pre.code code * {\n\tfont-size: 1em;\n}\n\npre.code code, pre.code code * {\n\tpadding: 0 !important;\n\tmargin: 0 !important;\n}\n\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.2.0\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /usr/local/etc/mavenrc ] ; then\n    . /usr/local/etc/mavenrc\n  fi\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"$(uname)\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        JAVA_HOME=\"$(/usr/libexec/java_home)\"; export JAVA_HOME\n      else\n        JAVA_HOME=\"/Library/Java/Home\"; export JAVA_HOME\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=$(java-config --jre-home)\n  fi\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=$(cygpath --unix \"$JAVA_HOME\")\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=$(cygpath --path --unix \"$CLASSPATH\")\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$JAVA_HOME\" ] && [ -d \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"$(cd \"$JAVA_HOME\" || (echo \"cannot cd into $JAVA_HOME.\"; exit 1); pwd)\"\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"$(which javac)\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"$(expr \"\\\"$javaExecutable\\\"\" : '\\([^ ]*\\)')\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=$(which readlink)\n    if [ ! \"$(expr \"$readLink\" : '\\([^ ]*\\)')\" = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"$(dirname \"\\\"$javaExecutable\\\"\")\"\n        javaExecutable=\"$(cd \"\\\"$javaHome\\\"\" && pwd -P)/javac\"\n      else\n        javaExecutable=\"$(readlink -f \"\\\"$javaExecutable\\\"\")\"\n      fi\n      javaHome=\"$(dirname \"\\\"$javaExecutable\\\"\")\"\n      javaHome=$(expr \"$javaHome\" : '\\(.*\\)/bin')\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\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    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"$(\\unset -f command 2>/dev/null; \\command -v java)\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=$(cd \"$wdir/..\" || exit 1; pwd)\n    fi\n    # end of workaround\n  done\n  printf '%s' \"$(cd \"$basedir\" || exit 1; pwd)\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    # Remove \\r in case we run on Windows within Git Bash\n    # and check out the repository with auto CRLF management\n    # enabled. Otherwise, we may read lines that are delimited with\n    # \\r\\n and produce $'-Xarg\\r' rather than -Xarg due to word\n    # splitting rules.\n    tr -s '\\r\\n' ' ' < \"$1\"\n  fi\n}\n\nlog() {\n  if [ \"$MVNW_VERBOSE\" = true ]; then\n    printf '%s\\n' \"$1\"\n  fi\n}\n\nBASE_DIR=$(find_maven_basedir \"$(dirname \"$0\")\")\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\nMAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}; export MAVEN_PROJECTBASEDIR\nlog \"$MAVEN_PROJECTBASEDIR\"\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nwrapperJarPath=\"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\"\nif [ -r \"$wrapperJarPath\" ]; then\n    log \"Found $wrapperJarPath\"\nelse\n    log \"Couldn't find $wrapperJarPath, downloading it ...\"\n\n    if [ -n \"$MVNW_REPOURL\" ]; then\n      wrapperUrl=\"$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar\"\n    else\n      wrapperUrl=\"https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar\"\n    fi\n    while IFS=\"=\" read -r key value; do\n      # Remove '\\r' from value to allow usage on windows as IFS does not consider '\\r' as a separator ( considers space, tab, new line ('\\n'), and custom '=' )\n      safeValue=$(echo \"$value\" | tr -d '\\r')\n      case \"$key\" in (wrapperUrl) wrapperUrl=\"$safeValue\"; break ;;\n      esac\n    done < \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties\"\n    log \"Downloading from: $wrapperUrl\"\n\n    if $cygwin; then\n      wrapperJarPath=$(cygpath --path --windows \"$wrapperJarPath\")\n    fi\n\n    if command -v wget > /dev/null; then\n        log \"Found wget ... using wget\"\n        [ \"$MVNW_VERBOSE\" = true ] && QUIET=\"\" || QUIET=\"--quiet\"\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            wget $QUIET \"$wrapperUrl\" -O \"$wrapperJarPath\" || rm -f \"$wrapperJarPath\"\n        else\n            wget $QUIET --http-user=\"$MVNW_USERNAME\" --http-password=\"$MVNW_PASSWORD\" \"$wrapperUrl\" -O \"$wrapperJarPath\" || rm -f \"$wrapperJarPath\"\n        fi\n    elif command -v curl > /dev/null; then\n        log \"Found curl ... using curl\"\n        [ \"$MVNW_VERBOSE\" = true ] && QUIET=\"\" || QUIET=\"--silent\"\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            curl $QUIET -o \"$wrapperJarPath\" \"$wrapperUrl\" -f -L || rm -f \"$wrapperJarPath\"\n        else\n            curl $QUIET --user \"$MVNW_USERNAME:$MVNW_PASSWORD\" -o \"$wrapperJarPath\" \"$wrapperUrl\" -f -L || rm -f \"$wrapperJarPath\"\n        fi\n    else\n        log \"Falling back to using Java to download\"\n        javaSource=\"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        javaClass=\"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class\"\n        # For Cygwin, switch paths to Windows format before running javac\n        if $cygwin; then\n          javaSource=$(cygpath --path --windows \"$javaSource\")\n          javaClass=$(cygpath --path --windows \"$javaClass\")\n        fi\n        if [ -e \"$javaSource\" ]; then\n            if [ ! -e \"$javaClass\" ]; then\n                log \" - Compiling MavenWrapperDownloader.java ...\"\n                (\"$JAVA_HOME/bin/javac\" \"$javaSource\")\n            fi\n            if [ -e \"$javaClass\" ]; then\n                log \" - Running MavenWrapperDownloader.java ...\"\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$wrapperUrl\" \"$wrapperJarPath\") || rm -f \"$wrapperJarPath\"\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\n# If specified, validate the SHA-256 sum of the Maven wrapper jar file\nwrapperSha256Sum=\"\"\nwhile IFS=\"=\" read -r key value; do\n  case \"$key\" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;\n  esac\ndone < \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties\"\nif [ -n \"$wrapperSha256Sum\" ]; then\n  wrapperSha256Result=false\n  if command -v sha256sum > /dev/null; then\n    if echo \"$wrapperSha256Sum  $wrapperJarPath\" | sha256sum -c > /dev/null 2>&1; then\n      wrapperSha256Result=true\n    fi\n  elif command -v shasum > /dev/null; then\n    if echo \"$wrapperSha256Sum  $wrapperJarPath\" | shasum -a 256 -c > /dev/null 2>&1; then\n      wrapperSha256Result=true\n    fi\n  else\n    echo \"Checksum validation was requested but neither 'sha256sum' or 'shasum' are available.\"\n    echo \"Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties.\"\n    exit 1\n  fi\n  if [ $wrapperSha256Result = false ]; then\n    echo \"Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.\" >&2\n    echo \"Investigate or delete $wrapperJarPath to attempt a clean download.\" >&2\n    echo \"If you updated your Maven version, you need to update the specified wrapperSha256Sum property.\" >&2\n    exit 1\n  fi\nfi\n\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=$(cygpath --path --windows \"$JAVA_HOME\")\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=$(cygpath --path --windows \"$CLASSPATH\")\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=$(cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\")\nfi\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $*\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n# shellcheck disable=SC2086 # safe args\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  $MAVEN_DEBUG_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\r\n@REM Licensed to the Apache Software Foundation (ASF) under one\r\n@REM or more contributor license agreements.  See the NOTICE file\r\n@REM distributed with this work for additional information\r\n@REM regarding copyright ownership.  The ASF licenses this file\r\n@REM to you under the Apache License, Version 2.0 (the\r\n@REM \"License\"); you may not use this file except in compliance\r\n@REM with the License.  You may obtain a copy of the License at\r\n@REM\r\n@REM    http://www.apache.org/licenses/LICENSE-2.0\r\n@REM\r\n@REM Unless required by applicable law or agreed to in writing,\r\n@REM software distributed under the License is distributed on an\r\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\n@REM KIND, either express or implied.  See the License for the\r\n@REM specific language governing permissions and limitations\r\n@REM under the License.\r\n@REM ----------------------------------------------------------------------------\r\n\r\n@REM ----------------------------------------------------------------------------\r\n@REM Apache Maven Wrapper startup batch script, version 3.2.0\r\n@REM\r\n@REM Required ENV vars:\r\n@REM JAVA_HOME - location of a JDK home dir\r\n@REM\r\n@REM Optional ENV vars\r\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\r\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending\r\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\r\n@REM     e.g. to debug Maven itself, use\r\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\r\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\r\n@REM ----------------------------------------------------------------------------\r\n\r\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\r\n@echo off\r\n@REM set title of command window\r\ntitle %0\r\n@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'\r\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\r\n\r\n@REM set %HOME% to equivalent of $HOME\r\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\r\n\r\n@REM Execute a user defined script before this one\r\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\r\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\r\nif exist \"%USERPROFILE%\\mavenrc_pre.bat\" call \"%USERPROFILE%\\mavenrc_pre.bat\" %*\r\nif exist \"%USERPROFILE%\\mavenrc_pre.cmd\" call \"%USERPROFILE%\\mavenrc_pre.cmd\" %*\r\n:skipRcPre\r\n\r\n@setlocal\r\n\r\nset ERROR_CODE=0\r\n\r\n@REM To isolate internal variables from possible post scripts, we use another setlocal\r\n@setlocal\r\n\r\n@REM ==== START VALIDATION ====\r\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\r\n\r\necho.\r\necho Error: JAVA_HOME not found in your environment. >&2\r\necho Please set the JAVA_HOME variable in your environment to match the >&2\r\necho location of your Java installation. >&2\r\necho.\r\ngoto error\r\n\r\n:OkJHome\r\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\r\n\r\necho.\r\necho Error: JAVA_HOME is set to an invalid directory. >&2\r\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\r\necho Please set the JAVA_HOME variable in your environment to match the >&2\r\necho location of your Java installation. >&2\r\necho.\r\ngoto error\r\n\r\n@REM ==== END VALIDATION ====\r\n\r\n:init\r\n\r\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\r\n@REM Fallback to current working directory if not found.\r\n\r\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\r\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\r\n\r\nset EXEC_DIR=%CD%\r\nset WDIR=%EXEC_DIR%\r\n:findBaseDir\r\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\r\ncd ..\r\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\r\nset WDIR=%CD%\r\ngoto findBaseDir\r\n\r\n:baseDirFound\r\nset MAVEN_PROJECTBASEDIR=%WDIR%\r\ncd \"%EXEC_DIR%\"\r\ngoto endDetectBaseDir\r\n\r\n:baseDirNotFound\r\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\r\ncd \"%EXEC_DIR%\"\r\n\r\n:endDetectBaseDir\r\n\r\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\r\n\r\n@setlocal EnableExtensions EnableDelayedExpansion\r\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\r\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\r\n\r\n:endReadAdditionalConfig\r\n\r\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\r\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\r\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\r\n\r\nset WRAPPER_URL=\"https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar\"\r\n\r\nFOR /F \"usebackq tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\r\n    IF \"%%A\"==\"wrapperUrl\" SET WRAPPER_URL=%%B\r\n)\r\n\r\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\r\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\r\nif exist %WRAPPER_JAR% (\r\n    if \"%MVNW_VERBOSE%\" == \"true\" (\r\n        echo Found %WRAPPER_JAR%\r\n    )\r\n) else (\r\n    if not \"%MVNW_REPOURL%\" == \"\" (\r\n        SET WRAPPER_URL=\"%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar\"\r\n    )\r\n    if \"%MVNW_VERBOSE%\" == \"true\" (\r\n        echo Couldn't find %WRAPPER_JAR%, downloading it ...\r\n        echo Downloading from: %WRAPPER_URL%\r\n    )\r\n\r\n    powershell -Command \"&{\"^\r\n\t\t\"$webclient = new-object System.Net.WebClient;\"^\r\n\t\t\"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {\"^\r\n\t\t\"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');\"^\r\n\t\t\"}\"^\r\n\t\t\"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')\"^\r\n\t\t\"}\"\r\n    if \"%MVNW_VERBOSE%\" == \"true\" (\r\n        echo Finished downloading %WRAPPER_JAR%\r\n    )\r\n)\r\n@REM End of extension\r\n\r\n@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file\r\nSET WRAPPER_SHA_256_SUM=\"\"\r\nFOR /F \"usebackq tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\r\n    IF \"%%A\"==\"wrapperSha256Sum\" SET WRAPPER_SHA_256_SUM=%%B\r\n)\r\nIF NOT %WRAPPER_SHA_256_SUM%==\"\" (\r\n    powershell -Command \"&{\"^\r\n       \"$hash = (Get-FileHash \\\"%WRAPPER_JAR%\\\" -Algorithm SHA256).Hash.ToLower();\"^\r\n       \"If('%WRAPPER_SHA_256_SUM%' -ne $hash){\"^\r\n       \"  Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';\"^\r\n       \"  Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';\"^\r\n       \"  Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';\"^\r\n       \"  exit 1;\"^\r\n       \"}\"^\r\n       \"}\"\r\n    if ERRORLEVEL 1 goto error\r\n)\r\n\r\n@REM Provide a \"standardized\" way to retrieve the CLI args that will\r\n@REM work with both Windows and non-Windows executions.\r\nset MAVEN_CMD_LINE_ARGS=%*\r\n\r\n%MAVEN_JAVA_EXE% ^\r\n  %JVM_CONFIG_MAVEN_PROPS% ^\r\n  %MAVEN_OPTS% ^\r\n  %MAVEN_DEBUG_OPTS% ^\r\n  -classpath %WRAPPER_JAR% ^\r\n  \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" ^\r\n  %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\r\nif ERRORLEVEL 1 goto error\r\ngoto end\r\n\r\n:error\r\nset ERROR_CODE=1\r\n\r\n:end\r\n@endlocal & set ERROR_CODE=%ERROR_CODE%\r\n\r\nif not \"%MAVEN_SKIP_RC%\"==\"\" goto skipRcPost\r\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\r\nif exist \"%USERPROFILE%\\mavenrc_post.bat\" call \"%USERPROFILE%\\mavenrc_post.bat\"\r\nif exist \"%USERPROFILE%\\mavenrc_post.cmd\" call \"%USERPROFILE%\\mavenrc_post.cmd\"\r\n:skipRcPost\r\n\r\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\r\nif \"%MAVEN_BATCH_PAUSE%\"==\"on\" pause\r\n\r\nif \"%MAVEN_TERMINATE_CMD%\"==\"on\" exit %ERROR_CODE%\r\n\r\ncmd /C exit /B %ERROR_CODE%\r\n"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<artifactId>spring-cloud-build</artifactId>\n\t\t<version>5.0.2-SNAPSHOT</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<groupId>org.springframework.cloud</groupId>\n\t<artifactId>spring-cloud-task-parent</artifactId>\n\t<version>5.0.2-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<name>Spring Cloud Task Build</name>\n\t<description>Spring Cloud Task Build</description>\n\t<url>https://cloud.spring.io/spring-cloud-task/</url>\n\t<organization>\n\t\t<name>VMware, Inc.</name>\n\t\t<url>https://www.spring.io</url>\n\t</organization>\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache License, Version 2.0</name>\n\t\t\t<url>https://www.apache.org/licenses/LICENSE-2.0</url>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<url>https://github.com/spring-cloud/spring-cloud-task</url>\n\t</scm>\n\t<developers>\n\t\t<developer>\n\t\t\t<id>mminella</id>\n\t\t\t<name>Michael Minella</name>\n\t\t\t<email>mminella at vmware.com</email>\n\t\t\t<organization>VMware, Inc.</organization>\n\t\t\t<organizationUrl>https://www.spring.io</organizationUrl>\n\t\t\t<roles>\n\t\t\t\t<role>Project Lead</role>\n\t\t\t</roles>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<id>cppwfs</id>\n\t\t\t<name>Glenn Renfro</name>\n\t\t\t<email>grenfro at vmware</email>\n\t\t\t<organization>VMware, Inc.</organization>\n\t\t\t<organizationUrl>https://www.spring.io</organizationUrl>\n\t\t</developer>\n\t</developers>\n\t<prerequisites>\n\t\t<maven>3.2.1</maven>\n\t</prerequisites>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-starter-stream-rabbit</artifactId>\n\t\t\t\t<version>${spring-cloud-stream-binder-rabbit.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-stream</artifactId>\n\t\t\t\t<version>${spring-cloud-stream.version}</version>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<distributionManagement>\n\t\t<site>\n\t\t\t<id>spring-docs</id>\n\t\t\t<url>https://docs.spring.io/spring-cloud-release/docs/${pom.version}/reference/html/</url>\n\t\t</site>\n\t\t<downloadUrl>https://github.com/spring-cloud/spring-cloud-release</downloadUrl>\n\t</distributionManagement>\n\n\t<modules>\n\t\t<module>spring-cloud-task-dependencies</module>\n\t\t<module>spring-cloud-task-core</module>\n\t\t<module>spring-cloud-task-batch</module>\n\t\t<module>spring-cloud-task-stream</module>\n\t\t<module>spring-cloud-starter-task</module>\n\t\t<module>spring-cloud-task-samples</module>\n\t\t<module>spring-cloud-task-integration-tests</module>\n\t\t<module>docs</module>\n\t\t<module>spring-cloud-starter-single-step-batch-job</module>\n\t</modules>\n\n\t<properties>\n\n\t\t<spring-cloud-stream.version>5.0.2-SNAPSHOT</spring-cloud-stream.version>\n\t\t<spring-cloud-stream-binder-rabbit.version>${spring-cloud-stream.version}\n\t\t</spring-cloud-stream-binder-rabbit.version>\n\t\t<jakarta-ee-api.version>11.0.0</jakarta-ee-api.version>\n\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<sonar.jacoco.reportPath>\n\t\t\t${project.build.directory}/coverage-reports/jacoco-ut.exec\n\t\t</sonar.jacoco.reportPath>\n\t\t<maven-checkstyle-plugin.failsOnError>true</maven-checkstyle-plugin.failsOnError>\n\t\t<maven-checkstyle-plugin.failsOnViolation>true\n\t\t</maven-checkstyle-plugin.failsOnViolation>\n\t\t<maven-checkstyle-plugin.includeTestSourceDirectory>true\n\t\t</maven-checkstyle-plugin.includeTestSourceDirectory>\n\t\t<java.version>17</java.version>\n\t\t<spring-javaformat-maven-plugin.version>0.0.40</spring-javaformat-maven-plugin.version>\n\t</properties>\n\n\t<build>\n\t\t<pluginManagement>\n\t\t\t<plugins>\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t\t<artifactId>flatten-maven-plugin</artifactId>\n\t\t\t\t</plugin>\n\t\t\t</plugins>\n\t\t</pluginManagement>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t<artifactId>flatten-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<includes>\n\t\t\t\t\t\t<include>**/*Tests.java</include>\n\t\t\t\t\t</includes>\n\t\t\t\t\t<argLine>${surefireArgLine}</argLine>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>17</source>\n\t\t\t\t\t<target>17</target>\n\t\t\t\t\t<testSource>17</testSource>\n\t\t\t\t\t<testTarget>17</testTarget>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>17</source>\n\t\t\t\t\t<doclint>all,-missing</doclint>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<phase>prepare-package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>aggregate</id>\n\t\t\t\t\t\t<phase>prepare-package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>aggregate</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.jacoco</groupId>\n\t\t\t\t<artifactId>jacoco-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<!--\n\t\t\t\t\t\tPrepares the property pointing to the JaCoCo runtime agent which\n\t\t\t\t\t\tis passed as VM argument when Maven the Surefire plugin is executed.\n\t\t\t\t\t-->\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>pre-unit-test</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>prepare-agent</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<!-- Sets the path to the file which contains the execution data. -->\n\t\t\t\t\t\t\t<destFile>\n\t\t\t\t\t\t\t\t${project.build.directory}/coverage-reports/jacoco-ut.exec\n\t\t\t\t\t\t\t</destFile>\n\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\tSets the name of the property containing the settings\n\t\t\t\t\t\t\t\tfor JaCoCo runtime agent.\n\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t<propertyName>surefireArgLine</propertyName>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<!--\n\t\t\t\t\t\tEnsures that the code coverage report for unit tests is created after\n\t\t\t\t\t\tunit tests have been run.\n\t\t\t\t\t-->\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>post-unit-test</id>\n\t\t\t\t\t\t<phase>test</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>report</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<!-- Sets the path to the file which contains the execution data. -->\n\t\t\t\t\t\t\t<dataFile>\n\t\t\t\t\t\t\t\t${project.build.directory}/coverage-reports/jacoco-ut.exec\n\t\t\t\t\t\t\t</dataFile>\n\t\t\t\t\t\t\t<!-- Sets the output directory for the code coverage report. -->\n\t\t\t\t\t\t\t<outputDirectory>\n\t\t\t\t\t\t\t\t${project.reporting.outputDirectory}/jacoco-ut\n\t\t\t\t\t\t\t</outputDirectory>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<version>0.8.13</version>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-checkstyle-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>io.spring.javaformat</groupId>\n\t\t\t\t<artifactId>spring-javaformat-maven-plugin</artifactId>\n\t\t\t\t<version>${spring-javaformat-maven-plugin.version}</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>validate</phase>\n\t\t\t\t\t\t<inherited>true</inherited>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>validate</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n\t<reporting>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-checkstyle-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</reporting>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>central</id>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.sonatype.central</groupId>\n\t\t\t\t\t\t<artifactId>central-publishing-maven-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludeArtifacts>\n\t\t\t\t\t\t\t\t<artifact>spring-cloud-task-integration-tests</artifact>\n\t\t\t\t\t\t\t</excludeArtifacts>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>spring</id>\n\t\t\t<repositories>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>spring-snapshots</id>\n\t\t\t\t\t<name>Spring Snapshots</name>\n\t\t\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>spring-milestones</id>\n\t\t\t\t\t<name>Spring Milestones</name>\n\t\t\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>spring-releases</id>\n\t\t\t\t\t<name>Spring Releases</name>\n\t\t\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t</repositories>\n\t\t\t<pluginRepositories>\n\t\t\t\t<pluginRepository>\n\t\t\t\t\t<id>spring-snapshots</id>\n\t\t\t\t\t<name>Spring Snapshots</name>\n\t\t\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</pluginRepository>\n\t\t\t\t<pluginRepository>\n\t\t\t\t\t<id>spring-milestones</id>\n\t\t\t\t\t<name>Spring Milestones</name>\n\t\t\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</pluginRepository>\n\t\t\t\t<pluginRepository>\n\t\t\t\t\t<id>spring-releases</id>\n\t\t\t\t\t<name>Spring Releases</name>\n\t\t\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</pluginRepository>\n\t\t\t</pluginRepositories>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>withoutDockerTests</id>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludedGroups>DockerRequired</excludedGroups>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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\t<parent>\n\t\t<artifactId>spring-cloud-task-parent</artifactId>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<version>5.0.2-SNAPSHOT</version>\n\t</parent>\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<artifactId>spring-cloud-starter-single-step-batch-job</artifactId>\n\t<name>spring-cloud-starter-single-step-batch-job</name>\n\n\t<properties>\n\t\t<spring-cloud-commons.version>5.0.2-SNAPSHOT</spring-cloud-commons.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-task-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-jdbc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-batch</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.batch</groupId>\n\t\t\t<artifactId>spring-batch-infrastructure</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t\t<version>${spring-boot.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.batch</groupId>\n\t\t\t<artifactId>spring-batch-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-amqp</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.amqp</groupId>\n\t\t\t<artifactId>spring-rabbit</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers-rabbitmq</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>tools.jackson.core</groupId>\n\t\t\t<artifactId>jackson-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>tools.jackson.core</groupId>\n\t\t\t<artifactId>jackson-databind</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter-engine</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter-params</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.kafka</groupId>\n\t\t\t<artifactId>spring-kafka-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-kafka</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter-api</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.platform</groupId>\n\t\t\t<artifactId>junit-platform-launcher</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-test-support</artifactId>\n\t\t\t<version>${spring-cloud-commons.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\n</project>\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/RangeConverter.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure;\n\nimport org.springframework.batch.infrastructure.item.file.transform.Range;\nimport org.springframework.core.convert.converter.Converter;\n\n/**\n * Converter for taking properties of format {@code start-end} or {@code start} (where\n * start and end are both integers) and converting them into {@link Range} instances for\n * configuring a\n * {@link org.springframework.batch.infrastructure.item.file.FlatFileItemReader}.\n *\n * @author Michael Minella\n * @since 2.3\n */\npublic class RangeConverter implements Converter<String, Range> {\n\n\t@Override\n\tpublic Range convert(String source) {\n\t\tif (source == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tString[] columns = source.split(\"-\");\n\n\t\tif (columns.length == 1) {\n\t\t\tint start = Integer.parseInt(columns[0]);\n\t\t\treturn new Range(start);\n\t\t}\n\t\telse if (columns.length == 2) {\n\t\t\tint start = Integer.parseInt(columns[0]);\n\t\t\tint end = Integer.parseInt(columns[1]);\n\t\t\treturn new Range(start, end);\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalArgumentException(String\n\t\t\t\t.format(\"%s is in an illegal format.  Ranges must be specified as startIndex-endIndex\", source));\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/SingleStepJobAutoConfiguration.java",
    "content": "/*\n * Copyright 2019-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure;\n\nimport java.util.Map;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.Step;\nimport org.springframework.batch.core.step.builder.SimpleStepBuilder;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.infrastructure.item.ItemProcessor;\nimport org.springframework.batch.infrastructure.item.ItemReader;\nimport org.springframework.batch.infrastructure.item.ItemWriter;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureBefore;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.util.Assert;\n\n/**\n * Autoconfiguration to create a single step Spring Batch Job.\n *\n * @author Michael Minella\n * @since 2.3\n */\n@AutoConfiguration\n@EnableConfigurationProperties(SingleStepJobProperties.class)\n@AutoConfigureBefore(BatchAutoConfiguration.class)\npublic class SingleStepJobAutoConfiguration {\n\n\tprivate SingleStepJobProperties properties;\n\n\t@Autowired\n\tPlatformTransactionManager transactionManager;\n\n\t@Autowired\n\tJobRepository jobRepository;\n\n\t@Autowired(required = false)\n\tprivate ItemProcessor<Map<String, Object>, Map<String, Object>> itemProcessor;\n\n\tpublic SingleStepJobAutoConfiguration(SingleStepJobProperties properties, ApplicationContext context) {\n\n\t\tvalidateProperties(properties);\n\t\tthis.properties = properties;\n\t}\n\n\tprivate void validateProperties(SingleStepJobProperties properties) {\n\t\tAssert.hasText(properties.getJobName(), \"A job name is required\");\n\t\tAssert.hasText(properties.getStepName(), \"A step name is required\");\n\t\tAssert.notNull(properties.getChunkSize(), \"A chunk size is required\");\n\t\tAssert.isTrue(properties.getChunkSize() > 0, \"A chunk size greater than zero is required\");\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnProperty(prefix = \"spring.batch.job\", name = \"job-name\")\n\tpublic Job job(ItemReader<Map<String, Object>> itemReader, ItemWriter<Map<String, Object>> itemWriter) {\n\n\t\tSimpleStepBuilder<Map<String, Object>, Map<String, Object>> stepBuilder = new StepBuilder(\n\t\t\t\tthis.properties.getStepName(), this.jobRepository)\n\t\t\t.<Map<String, Object>, Map<String, Object>>chunk(this.properties.getChunkSize(), this.transactionManager)\n\t\t\t.reader(itemReader);\n\n\t\tstepBuilder.processor(this.itemProcessor);\n\n\t\tStep step = stepBuilder.writer(itemWriter).build();\n\n\t\treturn new JobBuilder(this.properties.getJobName(), this.jobRepository).start(step).build();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/SingleStepJobProperties.java",
    "content": "/*\n * Copyright 2019-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Properties to configure the step and job level properties for a single step job.\n *\n * @author Michael Minella\n * @since 2.3\n */\n@ConfigurationProperties(prefix = \"spring.batch.job\")\npublic class SingleStepJobProperties {\n\n\t/**\n\t * Name of the step in the single step job.\n\t */\n\tprivate String stepName;\n\n\t/**\n\t * The number of items to process per transaction or chunk.\n\t */\n\tprivate Integer chunkSize;\n\n\t/**\n\t * The name of the job.\n\t */\n\tprivate String jobName;\n\n\t/**\n\t * Name of the step in the single step job.\n\t * @return name\n\t */\n\tpublic String getStepName() {\n\t\treturn stepName;\n\t}\n\n\t/**\n\t * Set the name of the step.\n\t * @param stepName name\n\t */\n\tpublic void setStepName(String stepName) {\n\t\tthis.stepName = stepName;\n\t}\n\n\t/**\n\t * The number of items to process per transaction/chunk.\n\t * @return number of items\n\t */\n\tpublic Integer getChunkSize() {\n\t\treturn chunkSize;\n\t}\n\n\t/**\n\t * Set the number of items within a transaction/chunk.\n\t * @param chunkSize number of items\n\t */\n\tpublic void setChunkSize(Integer chunkSize) {\n\t\tthis.chunkSize = chunkSize;\n\t}\n\n\t/**\n\t * The name of the job.\n\t * @return name\n\t */\n\tpublic String getJobName() {\n\t\treturn jobName;\n\t}\n\n\t/**\n\t * Set the name of the job.\n\t * @param jobName name\n\t */\n\tpublic void setJobName(String jobName) {\n\t\tthis.jobName = jobName;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/flatfile/FlatFileItemReaderAutoConfiguration.java",
    "content": "/*\n * Copyright 2019-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.flatfile;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.infrastructure.item.file.FlatFileItemReader;\nimport org.springframework.batch.infrastructure.item.file.LineCallbackHandler;\nimport org.springframework.batch.infrastructure.item.file.LineMapper;\nimport org.springframework.batch.infrastructure.item.file.builder.FlatFileItemReaderBuilder;\nimport org.springframework.batch.infrastructure.item.file.mapping.FieldSetMapper;\nimport org.springframework.batch.infrastructure.item.file.separator.RecordSeparatorPolicy;\nimport org.springframework.batch.infrastructure.item.file.transform.FieldSet;\nimport org.springframework.batch.infrastructure.item.file.transform.LineTokenizer;\nimport org.springframework.batch.infrastructure.item.file.transform.Range;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.cloud.task.batch.autoconfigure.RangeConverter;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Autconfiguration for a {@code FlatFileItemReader}.\n *\n * @author Michael Minella\n * @author Glenn Renfro\n * @since 2.3\n */\n@AutoConfiguration\n@EnableConfigurationProperties(FlatFileItemReaderProperties.class)\n@AutoConfigureAfter(BatchAutoConfiguration.class)\npublic class FlatFileItemReaderAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(FlatFileItemReaderAutoConfiguration.class);\n\n\tprivate final FlatFileItemReaderProperties properties;\n\n\tpublic FlatFileItemReaderAutoConfiguration(FlatFileItemReaderProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.flatfileitemreader\", name = \"name\")\n\tpublic FlatFileItemReader<Map<String, Object>> itemReader(@Autowired(required = false) LineTokenizer lineTokenizer,\n\t\t\t@Autowired(required = false) FieldSetMapper<Map<String, Object>> fieldSetMapper,\n\t\t\t@Autowired(required = false) LineMapper<Map<String, Object>> lineMapper,\n\t\t\t@Autowired(required = false) LineCallbackHandler skippedLinesCallback,\n\t\t\t@Autowired(required = false) RecordSeparatorPolicy recordSeparatorPolicy) {\n\t\tFlatFileItemReaderBuilder<Map<String, Object>> mapFlatFileItemReaderBuilder = new FlatFileItemReaderBuilder<Map<String, Object>>()\n\t\t\t.name(this.properties.getName())\n\t\t\t.resource(this.properties.getResource())\n\t\t\t.saveState(this.properties.isSaveState())\n\t\t\t.maxItemCount(this.properties.getMaxItemCount())\n\t\t\t.currentItemCount(this.properties.getCurrentItemCount())\n\t\t\t.strict(this.properties.isStrict())\n\t\t\t.encoding(this.properties.getEncoding())\n\t\t\t.linesToSkip(this.properties.getLinesToSkip())\n\t\t\t.comments(this.properties.getComments().toArray(new String[this.properties.getComments().size()]));\n\n\t\tif (recordSeparatorPolicy != null) {\n\t\t\tmapFlatFileItemReaderBuilder.recordSeparatorPolicy(recordSeparatorPolicy);\n\t\t}\n\t\tmapFlatFileItemReaderBuilder.fieldSetMapper(fieldSetMapper);\n\t\tmapFlatFileItemReaderBuilder.lineMapper(lineMapper);\n\t\tmapFlatFileItemReaderBuilder.skippedLinesCallback(skippedLinesCallback);\n\n\t\tif (this.properties.isDelimited()) {\n\t\t\tmapFlatFileItemReaderBuilder.delimited()\n\t\t\t\t.quoteCharacter(this.properties.getQuoteCharacter())\n\t\t\t\t.delimiter(this.properties.getDelimiter())\n\t\t\t\t.includedFields(this.properties.getIncludedFields().toArray(new Integer[0]))\n\t\t\t\t.names(this.properties.getNames())\n\t\t\t\t.beanMapperStrict(this.properties.isParsingStrict())\n\t\t\t\t.fieldSetMapper(new MapFieldSetMapper());\n\t\t}\n\t\telse if (this.properties.isFixedLength()) {\n\t\t\tRangeConverter rangeConverter = new RangeConverter();\n\t\t\tList<Range> ranges = new ArrayList<>();\n\t\t\tthis.properties.getRanges().forEach(range -> ranges.add(rangeConverter.convert(range)));\n\t\t\tmapFlatFileItemReaderBuilder.fixedLength()\n\t\t\t\t.columns(ranges.toArray(new Range[0]))\n\t\t\t\t.names(this.properties.getNames())\n\t\t\t\t.fieldSetMapper(new MapFieldSetMapper())\n\t\t\t\t.beanMapperStrict(this.properties.isParsingStrict());\n\t\t}\n\t\telse {\n\t\t\tmapFlatFileItemReaderBuilder.lineTokenizer(lineTokenizer);\n\t\t}\n\n\t\tif (lineTokenizer != null && (this.properties.isDelimited() || this.properties.isFixedLength())) {\n\t\t\tlogger.warn(\"Custom LineTokenizer bean provided but will be ignored because \"\n\t\t\t\t\t+ \"delimited or fixed-length properties are configured. \"\n\t\t\t\t\t+ \"Remove the custom bean or clear delimited/fixedLength properties.\");\n\t\t}\n\n\t\treturn mapFlatFileItemReaderBuilder.build();\n\t}\n\n\t/**\n\t * A {@link FieldSetMapper} that takes a {@code FieldSet} and returns the\n\t * {@code Map<String, Object>} of its contents.\n\t */\n\tpublic static class MapFieldSetMapper implements FieldSetMapper<Map<String, Object>> {\n\n\t\t@Override\n\t\tpublic Map<String, Object> mapFieldSet(FieldSet fieldSet) {\n\t\t\tMap<String, Object> map = new HashMap<>();\n\t\t\tfieldSet.getProperties().forEach((key, value) -> map.put(key.toString(), value));\n\t\t\treturn map;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/flatfile/FlatFileItemReaderProperties.java",
    "content": "/*\n * Copyright 2019-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.flatfile;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.batch.infrastructure.item.file.FlatFileItemReader;\nimport org.springframework.batch.infrastructure.item.file.transform.DelimitedLineTokenizer;\nimport org.springframework.batch.infrastructure.item.file.transform.Range;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.io.Resource;\n\n/**\n * Properties to configure a {@code FlatFileItemReader}.\n *\n * @author Michael Minella\n * @since 2.3\n */\n@ConfigurationProperties(prefix = \"spring.batch.job.flatfileitemreader\")\npublic class FlatFileItemReaderProperties {\n\n\t/**\n\t * Determines whether the state of the reader is persisted. Default is {@code true}.\n\t */\n\tprivate boolean saveState = true;\n\n\t/**\n\t * The name used to calculate the key within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext}. Required if\n\t * {@link #setSaveState} is set to {@code true}.\n\t */\n\tprivate String name;\n\n\t/**\n\t * Configure the maximum number of items to be read.\n\t */\n\tprivate int maxItemCount = Integer.MAX_VALUE;\n\n\t/**\n\t * Index for the current item. Also used on restarts to indicate where to start from.\n\t */\n\tprivate int currentItemCount = 0;\n\n\t/**\n\t * A list of {@code String} elements used to indicate which records are comments.\n\t */\n\tprivate List<String> comments = new ArrayList<>();\n\n\t/**\n\t * The {@link Resource} to be used as input.\n\t */\n\tprivate Resource resource;\n\n\t/**\n\t * Configure whether the reader should be in strict mode (require the input\n\t * {@link Resource} to exist).\n\t */\n\tprivate boolean strict = true;\n\n\t/**\n\t * Configure the encoding used by the reader to read the input source. The default\n\t * value is {@link FlatFileItemReader#DEFAULT_CHARSET}.\n\t */\n\tprivate String encoding = FlatFileItemReader.DEFAULT_CHARSET;\n\n\t/**\n\t * The number of lines to skip at the beginning of reading the file.\n\t */\n\tprivate int linesToSkip = 0;\n\n\t/**\n\t * Indicates that a {@link DelimitedLineTokenizer} should be used to parse each line.\n\t */\n\tprivate boolean delimited = false;\n\n\t/**\n\t * Define the delimiter for the file.\n\t */\n\tprivate String delimiter = DelimitedLineTokenizer.DELIMITER_COMMA;\n\n\t/**\n\t * Define the character used to quote fields.\n\t */\n\tprivate char quoteCharacter = DelimitedLineTokenizer.DEFAULT_QUOTE_CHARACTER;\n\n\t/**\n\t * A list of indices of the fields within a delimited file to be included.\n\t */\n\tprivate List<Integer> includedFields = new ArrayList<>();\n\n\t/**\n\t * Indicates that a\n\t * {@link org.springframework.batch.infrastructure.item.file.transform.FixedLengthTokenizer}\n\t * should be used to parse the records in the file.\n\t */\n\tprivate boolean fixedLength = false;\n\n\t/**\n\t * The column ranges to be used to parse a fixed width file.\n\t */\n\tprivate List<String> ranges = new ArrayList<>();\n\n\t/**\n\t * The names of the fields to be parsed from the file.\n\t */\n\tprivate String[] names;\n\n\t/**\n\t * Indicates whether the number of tokens must match the number of configured fields.\n\t */\n\tprivate boolean parsingStrict = true;\n\n\t/**\n\t * Returns the configured value of if the state of the reader will be persisted.\n\t * @return true if the state will be persisted\n\t */\n\tpublic boolean isSaveState() {\n\t\treturn this.saveState;\n\t}\n\n\t/**\n\t * Configure if the state of the\n\t * {@link org.springframework.batch.infrastructure.item.ItemStreamSupport} should be\n\t * persisted within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext} for restart\n\t * purposes.\n\t * @param saveState defaults to true\n\t */\n\tpublic void setSaveState(boolean saveState) {\n\t\tthis.saveState = saveState;\n\t}\n\n\t/**\n\t * Returns the configured value of the name used to calculate {@code ExecutionContext}\n\t * keys.\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * The name used to calculate the key within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext}. Required if\n\t * {@link #setSaveState} is set to true.\n\t * @param name name of the reader instance\n\t * @see org.springframework.batch.infrastructure.item.ItemStreamSupport#setName(String)\n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * The maximum number of items to be read.\n\t * @return the configured number of items, defaults to Integer.MAX_VALUE\n\t */\n\tpublic int getMaxItemCount() {\n\t\treturn this.maxItemCount;\n\t}\n\n\t/**\n\t * Configure the max number of items to be read.\n\t * @param maxItemCount the max items to be read\n\t * @see org.springframework.batch.infrastructure.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)\n\t */\n\tpublic void setMaxItemCount(int maxItemCount) {\n\t\tthis.maxItemCount = maxItemCount;\n\t}\n\n\t/**\n\t * Provides the index of the current item.\n\t * @return item index\n\t */\n\tpublic int getCurrentItemCount() {\n\t\treturn this.currentItemCount;\n\t}\n\n\t/**\n\t * Index for the current item. Also used on restarts to indicate where to start from.\n\t * @param currentItemCount current index\n\t * @see org.springframework.batch.infrastructure.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)\n\t */\n\tpublic void setCurrentItemCount(int currentItemCount) {\n\t\tthis.currentItemCount = currentItemCount;\n\t}\n\n\t/**\n\t * List of {@code String} values used to indicate what records are comments.\n\t * @return list of comment indicators\n\t */\n\tpublic List<String> getComments() {\n\t\treturn this.comments;\n\t}\n\n\t/**\n\t * Takes a list of {@code String} elements used to indicate what records are comments.\n\t * @param comments strings used to indicate commented lines\n\t */\n\tpublic void setComments(List<String> comments) {\n\t\tthis.comments = comments;\n\t}\n\n\t/**\n\t * The input file for the {@code FlatFileItemReader}.\n\t * @return a Resource\n\t */\n\tpublic Resource getResource() {\n\t\treturn this.resource;\n\t}\n\n\t/**\n\t * The {@link Resource} to be used as input.\n\t * @param resource the input to the reader.\n\t * @see FlatFileItemReader#setResource(Resource)\n\t */\n\tpublic void setResource(Resource resource) {\n\t\tthis.resource = resource;\n\t}\n\n\t/**\n\t * Returns true if a missing input file is considered an error.\n\t * @return true if the input file is required.\n\t */\n\tpublic boolean isStrict() {\n\t\treturn this.strict;\n\t}\n\n\t/**\n\t * Configure if the reader should be in strict mode (require the input\n\t * {@link Resource} to exist).\n\t * @param strict true if the input file is required to exist.\n\t * @see FlatFileItemReader#setStrict(boolean)\n\t */\n\tpublic void setStrict(boolean strict) {\n\t\tthis.strict = strict;\n\t}\n\n\t/**\n\t * Returns the encoding for the input file. Defaults to\n\t * {@code FlatFileItemReader#DEFAULT_CHARSET}.\n\t * @return the configured encoding\n\t */\n\tpublic String getEncoding() {\n\t\treturn this.encoding;\n\t}\n\n\t/**\n\t * Configure the encoding used by the reader to read the input source. Default value\n\t * is {@link FlatFileItemReader#DEFAULT_CHARSET}.\n\t * @param encoding to use to read the input source.\n\t * @see FlatFileItemReader#setEncoding(String)\n\t */\n\tpublic void setEncoding(String encoding) {\n\t\tthis.encoding = encoding;\n\t}\n\n\t/**\n\t * Number of lines to skip when reading the input file.\n\t * @return number of lines\n\t */\n\tpublic int getLinesToSkip() {\n\t\treturn this.linesToSkip;\n\t}\n\n\t/**\n\t * The number of lines to skip at the beginning of reading the file.\n\t * @param linesToSkip number of lines to be skipped.\n\t * @see FlatFileItemReader#setLinesToSkip(int)\n\t */\n\tpublic void setLinesToSkip(int linesToSkip) {\n\t\tthis.linesToSkip = linesToSkip;\n\t}\n\n\t/**\n\t * Indicates if the input file is a delimited file or not.\n\t * @return true if the file is delimited\n\t */\n\tpublic boolean isDelimited() {\n\t\treturn this.delimited;\n\t}\n\n\t/**\n\t * Indicates that a {@link DelimitedLineTokenizer} should be used to parse each line.\n\t * @param delimited true if the file is a delimited file\n\t */\n\tpublic void setDelimited(boolean delimited) {\n\t\tthis.delimited = delimited;\n\t}\n\n\t/**\n\t * The {@code String} used to divide the record into fields.\n\t * @return the delimiter\n\t */\n\tpublic String getDelimiter() {\n\t\treturn this.delimiter;\n\t}\n\n\t/**\n\t * Define the delimiter for the file.\n\t * @param delimiter String used as a delimiter between fields.\n\t * @see DelimitedLineTokenizer#setDelimiter(String)\n\t */\n\tpublic void setDelimiter(String delimiter) {\n\t\tthis.delimiter = delimiter;\n\t}\n\n\t/**\n\t * The char used to indicate that a field is quoted.\n\t * @return the quote char\n\t */\n\tpublic char getQuoteCharacter() {\n\t\treturn this.quoteCharacter;\n\t}\n\n\t/**\n\t * Define the character used to quote fields.\n\t * @param quoteCharacter char used to define quoted fields\n\t * @see DelimitedLineTokenizer#setQuoteCharacter(char)\n\t */\n\tpublic void setQuoteCharacter(char quoteCharacter) {\n\t\tthis.quoteCharacter = quoteCharacter;\n\t}\n\n\t/**\n\t * A {@code List} of indices indicating what fields to include.\n\t * @return list of indices\n\t */\n\tpublic List<Integer> getIncludedFields() {\n\t\treturn this.includedFields;\n\t}\n\n\t/**\n\t * A list of indices of the fields within a delimited file to be included.\n\t * @param includedFields indices of the fields\n\t * @see DelimitedLineTokenizer#setIncludedFields(int[])\n\t */\n\tpublic void setIncludedFields(List<Integer> includedFields) {\n\t\tthis.includedFields = includedFields;\n\t}\n\n\t/**\n\t * Indicates that a file contains records with fixed length columns.\n\t * @return true if the file is parsed using column indices\n\t */\n\tpublic boolean isFixedLength() {\n\t\treturn this.fixedLength;\n\t}\n\n\t/**\n\t * Indicates that a\n\t * {@link org.springframework.batch.infrastructure.item.file.transform.FixedLengthTokenizer}\n\t * should be used to parse the records in the file.\n\t * @param fixedLength true if the records should be tokenized by column index\n\t */\n\tpublic void setFixedLength(boolean fixedLength) {\n\t\tthis.fixedLength = fixedLength;\n\t}\n\n\t/**\n\t * The column ranges to be used to parsed a fixed width file.\n\t * @return a list of {@link Range} instances\n\t */\n\tpublic List<String> getRanges() {\n\t\treturn this.ranges;\n\t}\n\n\t/**\n\t * Column ranges for each field.\n\t * @param ranges list of ranges in start-end format (end is optional)\n\t */\n\tpublic void setRanges(List<String> ranges) {\n\t\tthis.ranges = ranges;\n\t}\n\n\t/**\n\t * Names of each column.\n\t * @return names\n\t */\n\tpublic String[] getNames() {\n\t\treturn this.names;\n\t}\n\n\t/**\n\t * The names of the fields to be parsed from the file.\n\t * @param names names of fields\n\t */\n\tpublic void setNames(String[] names) {\n\t\tthis.names = names;\n\t}\n\n\t/**\n\t * Indicates if the number of tokens must match the number of configured fields.\n\t * @return true if they must match\n\t */\n\tpublic boolean isParsingStrict() {\n\t\treturn this.parsingStrict;\n\t}\n\n\t/**\n\t * Indicates if the number of tokens must match the number of configured fields.\n\t * @param parsingStrict true if they must match\n\t */\n\tpublic void setParsingStrict(boolean parsingStrict) {\n\t\tthis.parsingStrict = parsingStrict;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/flatfile/FlatFileItemWriterAutoConfiguration.java",
    "content": "/*\n * Copyright 2019-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.flatfile;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.springframework.batch.infrastructure.item.file.FlatFileFooterCallback;\nimport org.springframework.batch.infrastructure.item.file.FlatFileHeaderCallback;\nimport org.springframework.batch.infrastructure.item.file.FlatFileItemWriter;\nimport org.springframework.batch.infrastructure.item.file.builder.FlatFileItemWriterBuilder;\nimport org.springframework.batch.infrastructure.item.file.transform.FieldExtractor;\nimport org.springframework.batch.infrastructure.item.file.transform.LineAggregator;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.io.WritableResource;\n\n/**\n * Autoconfiguration for a {@code FlatFileItemWriter}.\n *\n * @author Michael Minella\n * @since 2.3\n */\n@AutoConfiguration\n@EnableConfigurationProperties(FlatFileItemWriterProperties.class)\n@AutoConfigureAfter(BatchAutoConfiguration.class)\npublic class FlatFileItemWriterAutoConfiguration {\n\n\tprivate FlatFileItemWriterProperties properties;\n\n\t@Autowired(required = false)\n\tprivate LineAggregator<Map<String, Object>> lineAggregator;\n\n\t@Autowired(required = false)\n\tprivate FieldExtractor<Map<String, Object>> fieldExtractor;\n\n\t@Autowired(required = false)\n\tprivate FlatFileHeaderCallback headerCallback;\n\n\t@Autowired(required = false)\n\tprivate FlatFileFooterCallback footerCallback;\n\n\tpublic FlatFileItemWriterAutoConfiguration(FlatFileItemWriterProperties properties) {\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.flatfileitemwriter\", name = \"name\")\n\tpublic FlatFileItemWriter<Map<String, Object>> itemWriter() {\n\n\t\tif (this.properties.isDelimited() && this.properties.isFormatted()) {\n\t\t\tthrow new IllegalStateException(\"An output file must be either delimited or formatted or a custom \"\n\t\t\t\t\t+ \"LineAggregator must be provided. Your current configuration specifies both delimited and formatted\");\n\t\t}\n\t\telse if ((this.properties.isFormatted() || this.properties.isDelimited()) && this.lineAggregator != null) {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"A LineAggregator must be configured if the \" + \"output is not formatted or delimited\");\n\t\t}\n\n\t\tFlatFileItemWriterBuilder<Map<String, Object>> builder = new FlatFileItemWriterBuilder<Map<String, Object>>()\n\t\t\t.name(this.properties.getName())\n\t\t\t.resource((WritableResource) this.properties.getResource())\n\t\t\t.append(this.properties.isAppend())\n\t\t\t.encoding(this.properties.getEncoding())\n\t\t\t.forceSync(this.properties.isForceSync())\n\t\t\t.lineSeparator(this.properties.getLineSeparator())\n\t\t\t.saveState(this.properties.isSaveState())\n\t\t\t.shouldDeleteIfEmpty(this.properties.isShouldDeleteIfEmpty())\n\t\t\t.shouldDeleteIfExists(this.properties.isShouldDeleteIfExists())\n\t\t\t.transactional(this.properties.isTransactional())\n\t\t\t.headerCallback(this.headerCallback)\n\t\t\t.footerCallback(this.footerCallback);\n\n\t\tif (this.properties.isDelimited()) {\n\t\t\tFlatFileItemWriterBuilder.DelimitedBuilder<Map<String, Object>> delimitedBuilder = builder.delimited()\n\t\t\t\t.delimiter(this.properties.getDelimiter());\n\n\t\t\tif (this.fieldExtractor != null) {\n\t\t\t\tdelimitedBuilder.fieldExtractor(this.fieldExtractor);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdelimitedBuilder.fieldExtractor(new MapFieldExtractor(this.properties.getNames()));\n\t\t\t}\n\t\t}\n\t\telse if (this.properties.isFormatted()) {\n\t\t\tFlatFileItemWriterBuilder.FormattedBuilder<Map<String, Object>> formattedBuilder = builder.formatted()\n\t\t\t\t.format(this.properties.getFormat())\n\t\t\t\t.locale(this.properties.getLocale())\n\t\t\t\t.maximumLength(this.properties.getMaximumLength())\n\t\t\t\t.minimumLength(this.properties.getMinimumLength());\n\n\t\t\tif (this.fieldExtractor != null) {\n\t\t\t\tformattedBuilder.fieldExtractor(this.fieldExtractor);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tformattedBuilder.fieldExtractor(new MapFieldExtractor(this.properties.getNames()));\n\t\t\t}\n\t\t}\n\t\telse if (this.lineAggregator != null) {\n\t\t\tbuilder.lineAggregator(this.lineAggregator);\n\t\t}\n\n\t\treturn builder.build();\n\t}\n\n\t/**\n\t * A {@code FieldExtractor} that converts a {@code Map<String, Object>} to the ordered\n\t * {@code Object[]} required to populate an output record.\n\t */\n\tpublic static class MapFieldExtractor implements FieldExtractor<Map<String, Object>> {\n\n\t\tprivate String[] names;\n\n\t\tpublic MapFieldExtractor(String[] names) {\n\t\t\tthis.names = names;\n\t\t}\n\n\t\t@Override\n\t\tpublic Object[] extract(Map<String, Object> item) {\n\n\t\t\tList<Object> fields = new ArrayList<>(item.size());\n\n\t\t\tfor (String name : this.names) {\n\t\t\t\tfields.add(item.get(name));\n\t\t\t}\n\n\t\t\treturn fields.toArray();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/flatfile/FlatFileItemWriterProperties.java",
    "content": "/*\n * Copyright 2019-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.flatfile;\n\nimport java.util.Locale;\n\nimport org.springframework.batch.infrastructure.item.file.FlatFileItemWriter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.io.Resource;\n\n/**\n * Properties for configuring a {@code FlatFileItemWriter}.\n *\n * @author Michael Minella\n * @since 2.3\n */\n@ConfigurationProperties(prefix = \"spring.batch.job.flatfileitemwriter\")\npublic class FlatFileItemWriterProperties {\n\n\t/**\n\t * The {@link Resource} to be used as output.\n\t */\n\tprivate Resource resource;\n\n\t/**\n\t * Configure the use of the {@code DelimitedLineAggregator} to generate the output per\n\t * item. Default is {@code false}.\n\t */\n\tprivate boolean delimited;\n\n\t/**\n\t * Indicates to use a {@code FormatterLineAggregator} to generate the output per item.\n\t * Default is {@code false}.\n\t */\n\tprivate boolean formatted;\n\n\t/**\n\t * Configure the format the {@code FormatterLineAggregator} uses for each item.\n\t */\n\tprivate String format;\n\n\t/**\n\t * Configure the {@code Locale} to use when generating the output.\n\t */\n\tprivate Locale locale = Locale.getDefault();\n\n\t/**\n\t * Configure the maximum record length. If 0, the size is unbounded.\n\t */\n\tprivate int maximumLength = 0;\n\n\t/**\n\t * Configure the minimum record length.\n\t */\n\tprivate int minimumLength = 0;\n\n\t/**\n\t * Configure the {@code String} used to delimit the fields in the output file.\n\t */\n\tprivate String delimiter = \",\";\n\n\t/**\n\t * File encoding for the output file. Defaults to\n\t * {@code FlatFileItemWriter.DEFAULT_CHARSET})\n\t */\n\tprivate String encoding = FlatFileItemWriter.DEFAULT_CHARSET;\n\n\t/**\n\t * A flag indicating that changes should be force-synced to disk on flush. Defaults to\n\t * {@code false}.\n\t */\n\tprivate boolean forceSync = false;\n\n\t/**\n\t * Names of the fields to be extracted into the output.\n\t */\n\tprivate String[] names;\n\n\t/**\n\t * Configure if the output file is found if it should be appended to. Defaults to\n\t * {@code false}.\n\t */\n\tprivate boolean append = false;\n\n\t/**\n\t * String used to separate lines in output. Defaults to the {@code System} property\n\t * {@code line.separator}.\n\t */\n\tprivate String lineSeparator = FlatFileItemWriter.DEFAULT_LINE_SEPARATOR;\n\n\t/**\n\t * The name used to calculate the key within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext}. Required if\n\t * {@link #setSaveState} is set to {@code true}.\n\t */\n\tprivate String name;\n\n\t/**\n\t * Returns the configured value of whether the state of the reader is persisted.\n\t */\n\tprivate boolean saveState = true;\n\n\t/**\n\t * Indicates whether the output file should be deleted if no output was written to it.\n\t * Defaults to {@code false}.\n\t */\n\tprivate boolean shouldDeleteIfEmpty = false;\n\n\t/**\n\t * Indicates whether an existing output file should be deleted on startup. Defaults to\n\t * {@code true}.\n\t */\n\tprivate boolean shouldDeleteIfExists = true;\n\n\t/**\n\t * Indicates whether flushing the buffer should be delayed while a transaction is\n\t * active. Defaults to {@code true}.\n\t */\n\tprivate boolean transactional = FlatFileItemWriter.DEFAULT_TRANSACTIONAL;\n\n\t/**\n\t * Returns the configured value of if the state of the reader will be persisted.\n\t * @return true if the state will be persisted\n\t */\n\tpublic boolean isSaveState() {\n\t\treturn this.saveState;\n\t}\n\n\t/**\n\t * Configure if the state of the\n\t * {@link org.springframework.batch.infrastructure.item.ItemStreamSupport} should be\n\t * persisted within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext} for restart\n\t * purposes.\n\t * @param saveState defaults to true\n\t */\n\tpublic void setSaveState(boolean saveState) {\n\t\tthis.saveState = saveState;\n\t}\n\n\t/**\n\t * Returns the configured value of the name used to calculate {@code ExecutionContext}\n\t * keys.\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * The name used to calculate the key within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext}. Required if\n\t * {@link #setSaveState} is set to true.\n\t * @param name name of the reader instance\n\t * @see org.springframework.batch.infrastructure.item.ItemStreamSupport#setName(String)\n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * The output file for the {@code FlatFileItemWriter}.\n\t * @return a {@code Resource}\n\t */\n\tpublic Resource getResource() {\n\t\treturn this.resource;\n\t}\n\n\t/**\n\t * The {@link Resource} to be used as output.\n\t * @param resource the input to the reader.\n\t * @see FlatFileItemWriter#setResource\n\t */\n\tpublic void setResource(Resource resource) {\n\t\tthis.resource = resource;\n\t}\n\n\t/**\n\t * Indicates of the output will be delimited by a configured string (, by default).\n\t * @return true if the output file is a delimited file\n\t */\n\tpublic boolean isDelimited() {\n\t\treturn delimited;\n\t}\n\n\t/**\n\t * Configure the use of the {@code DelimitedLineAggregator} to generate the output per\n\t * item.\n\t * @param delimited indicator if the file will be delimited or not\n\t */\n\tpublic void setDelimited(boolean delimited) {\n\t\tthis.delimited = delimited;\n\t}\n\n\t/**\n\t * When a file is delimited, this {@code String} will be used as the delimiter between\n\t * fields.\n\t * @return delimiter\n\t */\n\tpublic String getDelimiter() {\n\t\treturn delimiter;\n\t}\n\n\t/**\n\t * Configure the {@code String} used to delimit the fields in the output file.\n\t * @param delimiter {@code String} used to delimit the fields of the output file.\n\t */\n\tpublic void setDelimiter(String delimiter) {\n\t\tthis.delimiter = delimiter;\n\t}\n\n\t/**\n\t * Names of the fields to be extracted into the output.\n\t * @return An array of field names\n\t */\n\tpublic String[] getNames() {\n\t\treturn names;\n\t}\n\n\t/**\n\t * Provide an ordered array of field names used to generate the output of a file.\n\t * @param names An array of field names\n\t */\n\tpublic void setNames(String[] names) {\n\t\tthis.names = names;\n\t}\n\n\t/**\n\t * True if an output file is found and should be added onto instead of\n\t * replaced/deleted. False by default.\n\t * @return appending indicator\n\t */\n\tpublic boolean isAppend() {\n\t\treturn append;\n\t}\n\n\t/**\n\t * Configure if the output file is found if it should be appended to. Defaults to\n\t * false.\n\t * @param append true if the output file should be appended onto if found.\n\t */\n\tpublic void setAppend(boolean append) {\n\t\tthis.append = append;\n\t}\n\n\t/**\n\t * Indicates that the output file will use String formatting to generate the output.\n\t * @return true if the file will contain formatted records defaults to true\n\t */\n\tpublic boolean isFormatted() {\n\t\treturn formatted;\n\t}\n\n\t/**\n\t * Indicates to use a {@code FormatterLineAggregator} to generate the output per item.\n\t * @param formatted true if the output should be formatted via the\n\t * {@code FormatterLineAggregator}\n\t */\n\tpublic void setFormatted(boolean formatted) {\n\t\tthis.formatted = formatted;\n\t}\n\n\t/**\n\t * File encoding for the output file.\n\t * @return the configured encoding for the output file (Defaults to\n\t * {@code FlatFileItemWriter.DEFAULT_CHARSET})\n\t */\n\tpublic String getEncoding() {\n\t\treturn encoding;\n\t}\n\n\t/**\n\t * Configure encoding of the output file.\n\t * @param encoding output encoding\n\t */\n\tpublic void setEncoding(String encoding) {\n\t\tthis.encoding = encoding;\n\t}\n\n\t/**\n\t * A flag indicating that changes should be force-synced to disk on flush. Defaults to\n\t * false.\n\t * @return The current instance of the builder.\n\t */\n\tpublic boolean isForceSync() {\n\t\treturn forceSync;\n\t}\n\n\t/**\n\t * A flag indicating that changes should be force-synced to disk on flush. Defaults to\n\t * false.\n\t * @param forceSync value to set the flag to\n\t */\n\tpublic void setForceSync(boolean forceSync) {\n\t\tthis.forceSync = forceSync;\n\t}\n\n\t/**\n\t * String used to separate lines in output. Defaults to the System property\n\t * line.separator.\n\t * @return the separator string\n\t */\n\tpublic String getLineSeparator() {\n\t\treturn lineSeparator;\n\t}\n\n\t/**\n\t * Configure the {@code String} used to separate each line.\n\t * @param lineSeparator defaults to System's line.separator property\n\t */\n\tpublic void setLineSeparator(String lineSeparator) {\n\t\tthis.lineSeparator = lineSeparator;\n\t}\n\n\t/**\n\t * Indicates if the output file should be deleted if no output was written to it.\n\t * Defaults to false.\n\t * @return true if a file that is empty at the end of the step should be deleted.\n\t */\n\tpublic boolean isShouldDeleteIfEmpty() {\n\t\treturn shouldDeleteIfEmpty;\n\t}\n\n\t/**\n\t * Configure if an empty output file should be deleted once the step is complete.\n\t * Defaults to false.\n\t * @param shouldDeleteIfEmpty true if the file should be deleted if no items have been\n\t * written to it.\n\t */\n\tpublic void setShouldDeleteIfEmpty(boolean shouldDeleteIfEmpty) {\n\t\tthis.shouldDeleteIfEmpty = shouldDeleteIfEmpty;\n\t}\n\n\t/**\n\t * Indicates if an existing output file should be deleted on startup. Defaults to\n\t * true.\n\t * @return if an existing output file should be deleted.\n\t */\n\tpublic boolean isShouldDeleteIfExists() {\n\t\treturn shouldDeleteIfExists;\n\t}\n\n\t/**\n\t * Configures if an existing output file should be deleted on the start of the step.\n\t * Defaults to true.\n\t * @param shouldDeleteIfExists if true and an output file of a previous run is found,\n\t * it will be deleted.\n\t */\n\tpublic void setShouldDeleteIfExists(boolean shouldDeleteIfExists) {\n\t\tthis.shouldDeleteIfExists = shouldDeleteIfExists;\n\t}\n\n\t/**\n\t * Indicates if flushing the buffer should be delayed while a transaction is active.\n\t * Defaults to true.\n\t * @return flag indicating if flushing should be delayed during a transaction\n\t */\n\tpublic boolean isTransactional() {\n\t\treturn transactional;\n\t}\n\n\t/**\n\t * Configure if output should not be flushed to disk during an active transaction.\n\t * @param transactional defaults to true\n\t */\n\tpublic void setTransactional(boolean transactional) {\n\t\tthis.transactional = transactional;\n\t}\n\n\t/**\n\t * Format used with the {@code FormatterLineAggregator}.\n\t * @return the format for each item's output.\n\t */\n\tpublic String getFormat() {\n\t\treturn format;\n\t}\n\n\t/**\n\t * Configure the format the {@code FormatterLineAggregator} will use for each item.\n\t * @param format the format for each item's output.\n\t */\n\tpublic void setFormat(String format) {\n\t\tthis.format = format;\n\t}\n\n\t/**\n\t * The {@code Locale} used when generating the output file.\n\t * @return configured {@code Locale}. Defaults to {@code Locale.getDefault()}\n\t */\n\tpublic Locale getLocale() {\n\t\treturn locale;\n\t}\n\n\t/**\n\t * Configure the {@code Locale} to use when generating the output.\n\t * @param locale the configured {@code Locale}\n\t */\n\tpublic void setLocale(Locale locale) {\n\t\tthis.locale = locale;\n\t}\n\n\t/**\n\t * The longest a record is allowed to be. If 0, the maximum is unlimited.\n\t * @return the max record length allowed. Defaults to 0.\n\t */\n\tpublic int getMaximumLength() {\n\t\treturn maximumLength;\n\t}\n\n\t/**\n\t * Configure the maximum record length. If 0, the size is unbounded.\n\t * @param maximumLength the maximum record length allowed.\n\t */\n\tpublic void setMaximumLength(int maximumLength) {\n\t\tthis.maximumLength = maximumLength;\n\t}\n\n\t/**\n\t * The minimum record length.\n\t * @return the minimum record length allowed.\n\t */\n\tpublic int getMinimumLength() {\n\t\treturn minimumLength;\n\t}\n\n\t/**\n\t * Configure the minimum record length.\n\t * @param minimumLength the minimum record length.\n\t */\n\tpublic void setMinimumLength(int minimumLength) {\n\t\tthis.minimumLength = minimumLength;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/flatfile/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration classes for flat file item readers and writers in single-step batch\n * jobs.\n */\npackage org.springframework.cloud.task.batch.autoconfigure.flatfile;\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/jdbc/JDBCSingleStepDataSourceAutoConfiguration.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.jdbc;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.cloud.task.configuration.DefaultTaskConfigurer;\nimport org.springframework.cloud.task.configuration.TaskConfigurer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Primary;\n\n/**\n * Establishes the default {@link DataSource} for the Task when creating a\n * {@link DataSource} for\n * {@link org.springframework.batch.infrastructure.item.database.JdbcCursorItemReader} or\n * {@link org.springframework.batch.infrastructure.item.database.JdbcBatchItemWriter}.\n *\n * @author Glenn Renfro\n * @since 3.0\n */\nclass JDBCSingleStepDataSourceAutoConfiguration {\n\n\t@ConditionalOnMissingBean\n\t@Bean\n\tpublic TaskConfigurer myTaskConfigurer(DataSource dataSource) {\n\t\treturn new DefaultTaskConfigurer(dataSource);\n\t}\n\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.jdbcsinglestep.datasource\", name = \"enable\", havingValue = \"true\",\n\t\t\tmatchIfMissing = true)\n\t@ConditionalOnMissingBean(name = \"springDataSourceProperties\")\n\t@Bean(name = \"springDataSourceProperties\")\n\t@ConfigurationProperties(\"spring.datasource\")\n\t@Primary\n\tpublic DataSourceProperties springDataSourceProperties() {\n\t\treturn new DataSourceProperties();\n\t}\n\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.jdbcsinglestep.datasource\", name = \"enable\", havingValue = \"true\",\n\t\t\tmatchIfMissing = true)\n\t@Bean(name = \"springDataSource\")\n\t@Primary\n\tpublic DataSource dataSource(\n\t\t\t@Qualifier(\"springDataSourceProperties\") DataSourceProperties springDataSourceProperties) {\n\t\tDataSource dataSource = springDataSourceProperties.initializeDataSourceBuilder().build();\n\t\treturn dataSource;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/jdbc/JdbcBatchItemWriterAutoConfiguration.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.jdbc;\n\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.infrastructure.item.database.ItemPreparedStatementSetter;\nimport org.springframework.batch.infrastructure.item.database.ItemSqlParameterSourceProvider;\nimport org.springframework.batch.infrastructure.item.database.JdbcBatchItemWriter;\nimport org.springframework.batch.infrastructure.item.database.builder.JdbcBatchItemWriterBuilder;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\n\n/**\n * Autconfiguration for a {@code JdbcBatchItemWriter}.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @since 2.3\n */\n@AutoConfiguration\n@EnableConfigurationProperties(JdbcBatchItemWriterProperties.class)\n@AutoConfigureAfter(BatchAutoConfiguration.class)\n@Import(JDBCSingleStepDataSourceAutoConfiguration.class)\npublic class JdbcBatchItemWriterAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(JdbcBatchItemWriterAutoConfiguration.class);\n\n\t@Autowired(required = false)\n\tprivate ItemPreparedStatementSetter itemPreparedStatementSetter;\n\n\t@Autowired(required = false)\n\tprivate ItemSqlParameterSourceProvider itemSqlParameterSourceProvider;\n\n\t@Autowired\n\tApplicationContext applicationContext;\n\n\tprivate JdbcBatchItemWriterProperties properties;\n\n\tprivate DataSource dataSource;\n\n\tpublic JdbcBatchItemWriterAutoConfiguration(DataSource dataSource, JdbcBatchItemWriterProperties properties) {\n\t\tthis.dataSource = dataSource;\n\t\tthis.properties = properties;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.jdbcbatchitemwriter\", name = \"name\")\n\tpublic JdbcBatchItemWriter<Map<String, Object>> itemWriter() {\n\t\tDataSource writerDataSource = this.dataSource;\n\t\ttry {\n\t\t\twriterDataSource = this.applicationContext.getBean(\"jdbcBatchItemWriterSpringDataSource\", DataSource.class);\n\t\t}\n\t\tcatch (Exception ex) {\n\t\t\tlogger.info(\"Using Default Data Source for the JdbcBatchItemWriter\");\n\t\t}\n\n\t\tJdbcBatchItemWriterBuilder<Map<String, Object>> jdbcBatchItemWriterBuilder = new JdbcBatchItemWriterBuilder<Map<String, Object>>()\n\t\t\t.dataSource(writerDataSource)\n\t\t\t.sql(this.properties.getSql());\n\t\tif (this.itemPreparedStatementSetter != null) {\n\t\t\tjdbcBatchItemWriterBuilder.itemPreparedStatementSetter(this.itemPreparedStatementSetter);\n\t\t}\n\t\telse if (this.itemSqlParameterSourceProvider != null) {\n\t\t\tjdbcBatchItemWriterBuilder.itemSqlParameterSourceProvider(this.itemSqlParameterSourceProvider);\n\t\t}\n\t\telse {\n\t\t\tjdbcBatchItemWriterBuilder.columnMapped();\n\t\t}\n\t\tjdbcBatchItemWriterBuilder.assertUpdates(this.properties.isAssertUpdates());\n\t\treturn jdbcBatchItemWriterBuilder.build();\n\t}\n\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.jdbcbatchitemwriter.datasource\", name = \"enable\",\n\t\t\thavingValue = \"true\")\n\t@Bean(name = \"jdbcBatchItemWriterDataSourceProperties\")\n\t@ConfigurationProperties(\"jdbcbatchitemwriter.datasource\")\n\tpublic DataSourceProperties jdbcBatchItemWriterDataSourceProperties() {\n\t\treturn new DataSourceProperties();\n\t}\n\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.jdbcbatchitemwriter.datasource\", name = \"enable\",\n\t\t\thavingValue = \"true\")\n\t@Bean(name = \"jdbcBatchItemWriterSpringDataSource\")\n\tpublic DataSource writerDataSource(\n\t\t\t@Qualifier(\"jdbcBatchItemWriterDataSourceProperties\") DataSourceProperties writerDataSourceProperties) {\n\t\tDataSource result = writerDataSourceProperties.initializeDataSourceBuilder().build();\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/jdbc/JdbcBatchItemWriterProperties.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.jdbc;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Properties to configure a {@code JdbcBatchItemWriter}.\n *\n * @author Glenn Renfro\n * @since 2.3\n */\n@ConfigurationProperties(prefix = \"spring.batch.job.jdbcbatchitemwriter\")\npublic class JdbcBatchItemWriterProperties {\n\n\t/**\n\t * The name used to calculate the key within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext}.\n\t */\n\tprivate String name;\n\n\t/**\n\t * The SQL statement to be used to update the database.\n\t */\n\tprivate String sql;\n\n\t/**\n\t * If set to {@code true}, confirms that every insert results in the update of at\n\t * least one row in the database. Defaults to {@code true}.\n\t */\n\tprivate boolean assertUpdates = true;\n\n\t/**\n\t * @return The current sql statement used to update the database.\n\t */\n\tpublic String getSql() {\n\t\treturn sql;\n\t}\n\n\t/**\n\t * Sets the sql statement to be used to update the database.\n\t * @param sql the sql statement to be used.\n\t */\n\tpublic void setSql(String sql) {\n\t\tthis.sql = sql;\n\t}\n\n\t/**\n\t * @return if returns true then each insert will be confirmed to have at least one\n\t * insert in the database.\n\t */\n\tpublic boolean isAssertUpdates() {\n\t\treturn assertUpdates;\n\t}\n\n\t/**\n\t * If set to true, confirms that every insert results in the update of at least one\n\t * row in the database. Defaults to True\n\t */\n\tpublic void setAssertUpdates(boolean assertUpdates) {\n\t\tthis.assertUpdates = assertUpdates;\n\t}\n\n\t/**\n\t * Returns the configured value of the name used to calculate {@code ExecutionContext}\n\t * keys.\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\t/**\n\t * The name used to calculate the key within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext}.\n\t * @param name name of the writer instance\n\t * @see org.springframework.batch.infrastructure.item.ItemStreamSupport#setName(String)\n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/jdbc/JdbcCursorItemReaderAutoConfiguration.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.jdbc;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.infrastructure.item.database.JdbcCursorItemReader;\nimport org.springframework.batch.infrastructure.item.database.builder.JdbcCursorItemReaderBuilder;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.jdbc.core.PreparedStatementSetter;\nimport org.springframework.jdbc.core.RowMapper;\n\n/**\n * @author Michael Minella\n * @author Glenn Renfro\n * @since 2.3\n */\n@AutoConfiguration\n@EnableConfigurationProperties(JdbcCursorItemReaderProperties.class)\n@AutoConfigureAfter(BatchAutoConfiguration.class)\n@ConditionalOnProperty(prefix = \"spring.batch.job.jdbccursoritemreader\", name = \"name\")\n@Import(JDBCSingleStepDataSourceAutoConfiguration.class)\npublic class JdbcCursorItemReaderAutoConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(JdbcCursorItemReaderAutoConfiguration.class);\n\n\t@Autowired\n\tApplicationContext applicationContext;\n\n\tprivate final JdbcCursorItemReaderProperties properties;\n\n\tprivate final DataSource dataSource;\n\n\tpublic JdbcCursorItemReaderAutoConfiguration(JdbcCursorItemReaderProperties properties, DataSource dataSource) {\n\t\tthis.properties = properties;\n\t\tthis.dataSource = dataSource;\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tpublic JdbcCursorItemReader<Map<String, Object>> itemReader(\n\t\t\t@Autowired(required = false) RowMapper<Map<String, Object>> rowMapper,\n\t\t\t@Autowired(required = false) PreparedStatementSetter preparedStatementSetter) {\n\t\tDataSource readerDataSource = this.dataSource;\n\t\ttry {\n\t\t\treaderDataSource = this.applicationContext.getBean(\"jdbcCursorItemReaderSpringDataSource\",\n\t\t\t\t\tDataSource.class);\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tlogger.info(\"Using Default Data Source for the JdbcCursorItemReader\");\n\n\t\t}\n\t\treturn new JdbcCursorItemReaderBuilder<Map<String, Object>>().name(this.properties.getName())\n\t\t\t.currentItemCount(this.properties.getCurrentItemCount())\n\t\t\t.dataSource(readerDataSource)\n\t\t\t.driverSupportsAbsolute(this.properties.isDriverSupportsAbsolute())\n\t\t\t.fetchSize(this.properties.getFetchSize())\n\t\t\t.ignoreWarnings(this.properties.isIgnoreWarnings())\n\t\t\t.maxItemCount(this.properties.getMaxItemCount())\n\t\t\t.maxRows(this.properties.getMaxRows())\n\t\t\t.queryTimeout(this.properties.getQueryTimeout())\n\t\t\t.saveState(this.properties.isSaveState())\n\t\t\t.sql(this.properties.getSql())\n\t\t\t.rowMapper(rowMapper)\n\t\t\t.preparedStatementSetter(preparedStatementSetter)\n\t\t\t.verifyCursorPosition(this.properties.isVerifyCursorPosition())\n\t\t\t.useSharedExtendedConnection(this.properties.isUseSharedExtendedConnection())\n\t\t\t.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tpublic RowMapper<Map<String, Object>> rowMapper() {\n\t\treturn new MapRowMapper();\n\t}\n\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.jdbccursoritemreader.datasource\", name = \"enable\",\n\t\t\thavingValue = \"true\")\n\t@Bean(name = \"jdbcCursorItemReaderDataSourceProperties\")\n\t@ConfigurationProperties(\"jdbccursoritemreader.datasource\")\n\tpublic DataSourceProperties jdbcCursorItemReaderDataSourceProperties() {\n\t\treturn new DataSourceProperties();\n\t}\n\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.jdbccursoritemreader.datasource\", name = \"enable\",\n\t\t\thavingValue = \"true\")\n\t@Bean(name = \"jdbcCursorItemReaderSpringDataSource\")\n\tpublic DataSource readerDataSource(\n\t\t\t@Qualifier(\"jdbcCursorItemReaderDataSourceProperties\") DataSourceProperties readerDataSourceProperties) {\n\t\tDataSource result = readerDataSourceProperties.initializeDataSourceBuilder().build();\n\t\treturn result;\n\t}\n\n\tpublic static class MapRowMapper implements RowMapper<Map<String, Object>> {\n\n\t\t@Override\n\t\tpublic Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {\n\t\t\tMap<String, Object> item = new HashMap<>(rs.getMetaData().getColumnCount());\n\n\t\t\tfor (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {\n\t\t\t\titem.put(rs.getMetaData().getColumnName(i), rs.getObject(i));\n\t\t\t}\n\n\t\t\treturn item;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/jdbc/JdbcCursorItemReaderProperties.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.jdbc;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * @author Michael Minella\n * @since 2.3\n */\n@ConfigurationProperties(prefix = \"spring.batch.job.jdbccursoritemreader\")\npublic class JdbcCursorItemReaderProperties {\n\n\t/**\n\t * Configure whether the state of the\n\t * {@link org.springframework.batch.infrastructure.item.ItemStreamSupport} should be\n\t * persisted within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext} for restart\n\t * purposes. Defaults to {@code true}.\n\t */\n\tprivate boolean saveState = true;\n\n\t/**\n\t * Returns the configured value of the name used to calculate {@code ExecutionContext}\n\t * keys.\n\t */\n\tprivate String name;\n\n\t/**\n\t * Configure the maximum number of items to be read.\n\t */\n\tprivate int maxItemCount = Integer.MAX_VALUE;\n\n\t/**\n\t * Index for the current item. Also used on restarts to indicate where to start from.\n\t * Defaults to 0.\n\t */\n\tprivate int currentItemCount = 0;\n\n\t/**\n\t * The number of items to return each time the cursor fetches from the server.\n\t */\n\tprivate int fetchSize;\n\n\t/**\n\t * Sets the maximum number of rows to be read with this reader.\n\t */\n\tprivate int maxRows;\n\n\t/**\n\t * The time in milliseconds for the query to timeout.\n\t */\n\tprivate int queryTimeout;\n\n\t/**\n\t * Establishes whether SQL warnings should be ignored. Defaults to {@code false}.\n\t */\n\tprivate boolean ignoreWarnings;\n\n\t/**\n\t * Sets whether the cursor's position should be validated with each item read.\n\t * Defaults to {@code false}.\n\t */\n\tprivate boolean verifyCursorPosition;\n\n\t/**\n\t * Establishes {@code false} the driver supports absolute positioning of a cursor.\n\t * Defaults to {@code false}.\n\t */\n\tprivate boolean driverSupportsAbsolute;\n\n\t/**\n\t * Establishes whether the connection used for the cursor is being used by all other\n\t * processing and is, therefore, part of the same transaction. Defaults to\n\t * {@code false}\n\t */\n\tprivate boolean useSharedExtendedConnection;\n\n\t/**\n\t * The SQL query to be executed.\n\t */\n\tprivate String sql;\n\n\t/**\n\t * Returns the configured value of if the state of the reader will be persisted.\n\t * @return true if the state will be persisted\n\t */\n\tpublic boolean isSaveState() {\n\t\treturn this.saveState;\n\t}\n\n\t/**\n\t * Configure if the state of the\n\t * {@link org.springframework.batch.infrastructure.item.ItemStreamSupport} should be\n\t * persisted within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext} for restart\n\t * purposes.\n\t * @param saveState defaults to true\n\t */\n\tpublic void setSaveState(boolean saveState) {\n\t\tthis.saveState = saveState;\n\t}\n\n\t/**\n\t * Returns the configured value of the name used to calculate {@code ExecutionContext}\n\t * keys.\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * The name used to calculate the key within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext}. Required if\n\t * {@link #setSaveState} is set to true.\n\t * @param name name of the reader instance\n\t * @see org.springframework.batch.infrastructure.item.ItemStreamSupport#setName(String)\n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * The maximum number of items to be read.\n\t * @return the configured number of items, defaults to Integer.MAX_VALUE\n\t */\n\tpublic int getMaxItemCount() {\n\t\treturn this.maxItemCount;\n\t}\n\n\t/**\n\t * Configure the max number of items to be read.\n\t * @param maxItemCount the max items to be read\n\t * @see org.springframework.batch.infrastructure.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)\n\t */\n\tpublic void setMaxItemCount(int maxItemCount) {\n\t\tthis.maxItemCount = maxItemCount;\n\t}\n\n\t/**\n\t * Provides the index of the current item.\n\t * @return item index\n\t */\n\tpublic int getCurrentItemCount() {\n\t\treturn this.currentItemCount;\n\t}\n\n\t/**\n\t * Index for the current item. Also used on restarts to indicate where to start from.\n\t * @param currentItemCount current index\n\t * @see org.springframework.batch.infrastructure.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)\n\t */\n\tpublic void setCurrentItemCount(int currentItemCount) {\n\t\tthis.currentItemCount = currentItemCount;\n\t}\n\n\t/**\n\t * Provides the number of items to return each time the cursor fetches from the\n\t * server.\n\t * @return fetch size\n\t */\n\tpublic int getFetchSize() {\n\t\treturn fetchSize;\n\t}\n\n\t/**\n\t * Sets the number of items to return each time the cursor fetches from the server.\n\t * @param fetchSize the number of items\n\t * @see org.springframework.batch.infrastructure.item.database.builder.JdbcCursorItemReaderBuilder#fetchSize(int)\n\t */\n\tpublic void setFetchSize(int fetchSize) {\n\t\tthis.fetchSize = fetchSize;\n\t}\n\n\t/**\n\t * Provides the maximum number of rows to read with this reader.\n\t * @return maxiumum number of items\n\t */\n\tpublic int getMaxRows() {\n\t\treturn maxRows;\n\t}\n\n\t/**\n\t * Sets the maximum number of rows to be read with this reader.\n\t * @param maxRows maximum number of items\n\t * @see org.springframework.batch.infrastructure.item.database.builder.JdbcCursorItemReaderBuilder#maxRows(int)\n\t */\n\tpublic void setMaxRows(int maxRows) {\n\t\tthis.maxRows = maxRows;\n\t}\n\n\t/**\n\t * Provides the time in milliseconds for the query to timeout.\n\t * @return milliseconds for the timeout\n\t */\n\tpublic int getQueryTimeout() {\n\t\treturn queryTimeout;\n\t}\n\n\t/**\n\t * Sets the time in milliseconds for the query to timeout.\n\t * @param queryTimeout milliseconds\n\t * @see org.springframework.batch.infrastructure.item.database.builder.JdbcCursorItemReaderBuilder#queryTimeout(int)\n\t */\n\tpublic void setQueryTimeout(int queryTimeout) {\n\t\tthis.queryTimeout = queryTimeout;\n\t}\n\n\t/**\n\t * Provides if SQL warnings should be ignored.\n\t * @return true if warnings should be ignored\n\t */\n\tpublic boolean isIgnoreWarnings() {\n\t\treturn ignoreWarnings;\n\t}\n\n\t/**\n\t * Sets if SQL warnings should be ignored.\n\t * @param ignoreWarnings indicator if the warnings should be ignored\n\t * @see org.springframework.batch.infrastructure.item.database.builder.JdbcCursorItemReaderBuilder#ignoreWarnings(boolean)\n\t */\n\tpublic void setIgnoreWarnings(boolean ignoreWarnings) {\n\t\tthis.ignoreWarnings = ignoreWarnings;\n\t}\n\n\t/**\n\t * Indicates if the cursor's position should be validated with each item read (to\n\t * confirm that the RowMapper has not moved the cursor's location).\n\t * @return true if the position should be validated\n\t */\n\tpublic boolean isVerifyCursorPosition() {\n\t\treturn verifyCursorPosition;\n\t}\n\n\t/**\n\t * Provides if the cursor's position should be validated with each item read.\n\t * @param verifyCursorPosition true if the position should be validated\n\t * @see org.springframework.batch.infrastructure.item.database.builder.JdbcCursorItemReaderBuilder#verifyCursorPosition(boolean)\n\t */\n\tpublic void setVerifyCursorPosition(boolean verifyCursorPosition) {\n\t\tthis.verifyCursorPosition = verifyCursorPosition;\n\t}\n\n\t/**\n\t * Provides if the driver supports absolute positioning of a cursor.\n\t * @return true if the driver supports absolute positioning\n\t */\n\tpublic boolean isDriverSupportsAbsolute() {\n\t\treturn driverSupportsAbsolute;\n\t}\n\n\t/**\n\t * Sets if the driver supports absolute positioning of a cursor.\n\t * @param driverSupportsAbsolute true if the driver supports absolute positioning\n\t * @see org.springframework.batch.infrastructure.item.database.builder.JdbcCursorItemReaderBuilder#driverSupportsAbsolute(boolean)\n\t */\n\tpublic void setDriverSupportsAbsolute(boolean driverSupportsAbsolute) {\n\t\tthis.driverSupportsAbsolute = driverSupportsAbsolute;\n\t}\n\n\t/**\n\t * Sets whether the connection used for the cursor is being used by all other\n\t * processing and is, therefore, part of the same transaction.\n\t * @return true if the connection is shared beyond this query\n\t */\n\tpublic boolean isUseSharedExtendedConnection() {\n\t\treturn useSharedExtendedConnection;\n\t}\n\n\t/**\n\t * Sets whether the the connection used for the cursor is being used by all other\n\t * processing and is, therefore, part of the same transaction.\n\t * @param useSharedExtendedConnection true if the connection is shared beyond this\n\t * query\n\t * @see org.springframework.batch.infrastructure.item.database.builder.JdbcCursorItemReaderBuilder#useSharedExtendedConnection(boolean)\n\t */\n\tpublic void setUseSharedExtendedConnection(boolean useSharedExtendedConnection) {\n\t\tthis.useSharedExtendedConnection = useSharedExtendedConnection;\n\t}\n\n\t/**\n\t * Returns the SQL query to be executed.\n\t * @return the SQL query\n\t */\n\tpublic String getSql() {\n\t\treturn sql;\n\t}\n\n\t/**\n\t * Sets the SQL query to be executed.\n\t * @param sql the query\n\t * @see org.springframework.batch.infrastructure.item.database.builder.JdbcCursorItemReaderBuilder#sql(String)\n\t */\n\tpublic void setSql(String sql) {\n\t\tthis.sql = sql;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/jdbc/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration classes for JDBC item readers and writers in single-step batch jobs.\n */\npackage org.springframework.cloud.task.batch.autoconfigure.jdbc;\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/kafka/KafkaItemReaderAutoConfiguration.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.kafka;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport org.springframework.batch.infrastructure.item.kafka.KafkaItemReader;\nimport org.springframework.batch.infrastructure.item.kafka.builder.KafkaItemReaderBuilder;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.util.StringUtils;\n\n/**\n *\n * AutoConfiguration for a {@code KafkaItemReader}.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @since 2.3\n */\n@AutoConfiguration\n@EnableConfigurationProperties({ KafkaProperties.class, KafkaItemReaderProperties.class })\n@AutoConfigureAfter(BatchAutoConfiguration.class)\npublic class KafkaItemReaderAutoConfiguration {\n\n\t@Autowired\n\tprivate KafkaProperties kafkaProperties;\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.kafkaitemreader\", name = \"name\")\n\tpublic KafkaItemReader<Object, Map<String, Object>> kafkaItemReader(\n\t\t\tKafkaItemReaderProperties kafkaItemReaderProperties) {\n\t\tProperties consumerProperties = new Properties();\n\t\tconsumerProperties.putAll(this.kafkaProperties.getConsumer().buildProperties());\n\t\tvalidateProperties(kafkaItemReaderProperties);\n\t\tif (kafkaItemReaderProperties.getPartitions() == null\n\t\t\t\t|| kafkaItemReaderProperties.getPartitions().size() == 0) {\n\t\t\tkafkaItemReaderProperties.setPartitions(new ArrayList<>(1));\n\t\t\tkafkaItemReaderProperties.getPartitions().add(0);\n\t\t}\n\t\treturn new KafkaItemReaderBuilder<Object, Map<String, Object>>()\n\t\t\t.partitions(kafkaItemReaderProperties.getPartitions())\n\t\t\t.consumerProperties(consumerProperties)\n\t\t\t.name(kafkaItemReaderProperties.getName())\n\t\t\t.pollTimeout(Duration.ofSeconds(kafkaItemReaderProperties.getPollTimeOutInSeconds()))\n\t\t\t.saveState(kafkaItemReaderProperties.isSaveState())\n\t\t\t.topic(kafkaItemReaderProperties.getTopic())\n\t\t\t.build();\n\t}\n\n\tprivate void validateProperties(KafkaItemReaderProperties kafkaItemReaderProperties) {\n\t\tif (!StringUtils.hasText(kafkaItemReaderProperties.getName())) {\n\t\t\tthrow new IllegalArgumentException(\"Name must not be empty or null\");\n\t\t}\n\t\tif (!StringUtils.hasText(kafkaItemReaderProperties.getTopic())) {\n\t\t\tthrow new IllegalArgumentException(\"Topic must not be empty or null\");\n\t\t}\n\t\tif (!StringUtils.hasText(this.kafkaProperties.getConsumer().getGroupId())) {\n\t\t\tthrow new IllegalArgumentException(\"GroupId must not be empty or null\");\n\t\t}\n\t\tif (this.kafkaProperties.getBootstrapServers() == null\n\t\t\t\t|| this.kafkaProperties.getBootstrapServers().size() == 0) {\n\t\t\tthrow new IllegalArgumentException(\"Bootstrap Servers must be configured\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/kafka/KafkaItemReaderProperties.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.kafka;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Properties to configure a {@code KafkaItemReader}.\n *\n * @author Glenn Renfro\n * @since 2.3\n */\n@ConfigurationProperties(prefix = \"spring.batch.job.kafkaitemreader\")\npublic class KafkaItemReaderProperties {\n\n\t/**\n\t * The name used to calculate the key within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext}.\n\t */\n\tprivate String name;\n\n\t/**\n\t * The topic name from which the messages is read.\n\t */\n\tprivate String topic;\n\n\t/**\n\t * A list of partitions to manually assign to the consumer. Defaults to a single entry\n\t * value of 1.\n\t */\n\tprivate List<Integer> partitions = new ArrayList<>();\n\n\t/**\n\t * Establish the {@code pollTimeout} for the {@code poll()} operations. Defaults to 30\n\t * seconds.\n\t */\n\tprivate long pollTimeOutInSeconds = 30L;\n\n\t/**\n\t * Configure whether the state of the\n\t * {@link org.springframework.batch.infrastructure.item.ItemStreamSupport} should be\n\t * persisted within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext} for restart\n\t * purposes. Defaults to {@code true}.\n\t */\n\tprivate boolean saveState = true;\n\n\t/**\n\t * Returns the configured value of the name used to calculate {@code ExecutionContext}\n\t * keys.\n\t * @return the name\n\t */\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\t/**\n\t * The name used to calculate the key within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext}.\n\t * @param name name of the writer instance\n\t * @see org.springframework.batch.infrastructure.item.ItemStreamSupport#setName(String)\n\t */\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\t/**\n\t * Returns the name of the topic from which messages will be read.\n\t * @return the name of the topic.\n\t */\n\tpublic String getTopic() {\n\t\treturn topic;\n\t}\n\n\t/**\n\t * The topic name from which the messages will be read.\n\t * @param topic name of the topic\n\t */\n\tpublic void setTopic(String topic) {\n\t\tthis.topic = topic;\n\t}\n\n\t/**\n\t * A list of partitions to manually assign to the consumer. Defaults to a single entry\n\t * value of 1.\n\t * @return the list of partitions.\n\t */\n\tpublic List<Integer> getPartitions() {\n\t\treturn partitions;\n\t}\n\n\t/**\n\t * A list of partitions to manually assign to the consumer. Defaults to a single entry\n\t * value of 1.\n\t * @param partitions list of partitions\n\t */\n\tpublic void setPartitions(List<Integer> partitions) {\n\t\tthis.partitions = partitions;\n\t}\n\n\t/**\n\t * Get the pollTimeout for the poll() operations. Defaults to 30 seconds.\n\t * @return long containing the poll timeout.\n\t */\n\tpublic long getPollTimeOutInSeconds() {\n\t\treturn pollTimeOutInSeconds;\n\t}\n\n\t/**\n\t * Set the pollTimeout for the poll() operations. Defaults to 30 seconds.\n\t * @param pollTimeOutInSeconds the number of seconds to wait before timing out.\n\t */\n\tpublic void setPollTimeOutInSeconds(long pollTimeOutInSeconds) {\n\t\tthis.pollTimeOutInSeconds = pollTimeOutInSeconds;\n\t}\n\n\t/**\n\t * Configure if the state of the\n\t * {@link org.springframework.batch.infrastructure.item.ItemStreamSupport} should be\n\t * persisted within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext} for restart\n\t * purposes. Defaults to true.\n\t * @return current status of the saveState flag.\n\t */\n\tpublic boolean isSaveState() {\n\t\treturn saveState;\n\t}\n\n\t/**\n\t * Configure if the state of the\n\t * {@link org.springframework.batch.infrastructure.item.ItemStreamSupport} should be\n\t * persisted within the\n\t * {@link org.springframework.batch.infrastructure.item.ExecutionContext} for restart\n\t * purposes.\n\t * @param saveState true if state should be persisted. Defaults to true.\n\t */\n\tpublic void setSaveState(boolean saveState) {\n\t\tthis.saveState = saveState;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/kafka/KafkaItemWriterAutoConfiguration.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.kafka;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.springframework.batch.infrastructure.item.kafka.KafkaItemWriter;\nimport org.springframework.batch.infrastructure.item.kafka.builder.KafkaItemWriterBuilder;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.kafka.autoconfigure.KafkaProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.convert.converter.Converter;\nimport org.springframework.kafka.core.DefaultKafkaProducerFactory;\nimport org.springframework.kafka.core.KafkaTemplate;\nimport org.springframework.kafka.core.ProducerFactory;\nimport org.springframework.kafka.support.serializer.JacksonJsonSerializer;\nimport org.springframework.util.Assert;\n\n/**\n *\n * Autconfiguration for a {@code KafkaItemReader}.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @since 2.3\n */\n@AutoConfiguration\n@EnableConfigurationProperties({ KafkaProperties.class, KafkaItemWriterProperties.class })\n@AutoConfigureAfter(BatchAutoConfiguration.class)\npublic class KafkaItemWriterAutoConfiguration {\n\n\t@Autowired\n\tprivate KafkaProperties kafkaProperties;\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\t@ConditionalOnProperty(prefix = \"spring.batch.job.kafkaitemwriter\", name = \"topic\")\n\tpublic KafkaItemWriter<Object, Map<String, Object>> kafkaItemWriter(\n\t\t\tKafkaItemWriterProperties kafkaItemWriterProperties,\n\t\t\tProducerFactory<Object, Map<String, Object>> producerFactory,\n\t\t\t@Qualifier(\"batchItemKeyMapper\") Converter<Map<String, Object>, Object> itemKeyMapper) {\n\n\t\tvalidateProperties(kafkaItemWriterProperties);\n\t\tKafkaTemplate template = new KafkaTemplate(producerFactory);\n\t\ttemplate.setDefaultTopic(kafkaItemWriterProperties.getTopic());\n\t\treturn new KafkaItemWriterBuilder<Object, Map<String, Object>>().delete(kafkaItemWriterProperties.isDelete())\n\t\t\t.kafkaTemplate(template)\n\t\t\t.itemKeyMapper(itemKeyMapper)\n\t\t\t.build();\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean(name = \"batchItemKeyMapper\")\n\tpublic Converter<Map<String, Object>, Object> batchItemKeyMapper() {\n\t\treturn new Converter<Map<String, Object>, Object>() {\n\t\t\t@Override\n\t\t\tpublic Object convert(Map<String, Object> source) {\n\t\t\t\treturn source;\n\t\t\t}\n\t\t};\n\t}\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tProducerFactory<Object, Map<String, Object>> producerFactory() {\n\t\tMap<String, Object> configs = new HashMap<>();\n\t\tconfigs.putAll(this.kafkaProperties.getProducer().buildProperties());\n\t\treturn new DefaultKafkaProducerFactory<>(configs, null, new JacksonJsonSerializer());\n\t}\n\n\tprivate void validateProperties(KafkaItemWriterProperties kafkaItemWriterProperties) {\n\t\tAssert.hasText(kafkaItemWriterProperties.getTopic(), \"topic must not be empty or null\");\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/kafka/KafkaItemWriterProperties.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.kafka;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Properties to configure a {@code KafkaItemWriter}.\n *\n * @author Glenn Renfro\n * @since 2.3\n */\n@ConfigurationProperties(prefix = \"spring.batch.job.kafkaitemwriter\")\npublic class KafkaItemWriterProperties {\n\n\t/**\n\t * The topic name from which the messages are written.\n\t */\n\tprivate String topic;\n\n\t/**\n\t * Indicate whether the items being passed to the writer are all to be sent as delete\n\t * events to the topic. Defaults to {@code false}.\n\t */\n\tprivate boolean delete;\n\n\t/**\n\t * Returns the name of the topic from which messages will be written.\n\t * @return the name of the topic.\n\t */\n\tpublic String getTopic() {\n\t\treturn topic;\n\t}\n\n\t/**\n\t * The topic name from which the messages are written.\n\t * @param topic name of the topic\n\t */\n\tpublic void setTopic(String topic) {\n\t\tthis.topic = topic;\n\t}\n\n\t/**\n\t * Indicate if the items being passed to the writer are all to be sent as delete\n\t * events to the topic. A delete event is made of a key with a null value. If set to\n\t * false (default), the items will be sent with provided value and key converter by\n\t * the itemKeyMapper. If set to true, the items will be sent with the key converter\n\t * from the value by the itemKeyMapper and a null value.\n\t * @return removal indicator.\n\t */\n\tpublic boolean isDelete() {\n\t\treturn delete;\n\t}\n\n\t/**\n\t * Indicate if the items being passed to the writer are all to be sent as delete\n\t * events to the topic. A delete event is made of a key with a null value. If set to\n\t * false (default), the items will be sent with provided value and key converter by\n\t * the itemKeyMapper. If set to true, the items will be sent with the key converter\n\t * from the value by the itemKeyMapper and a null value.\n\t * @param delete removal indicator.\n\t */\n\tpublic void setDelete(boolean delete) {\n\t\tthis.delete = delete;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/kafka/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration classes for Kafka item readers and writers in single-step batch\n * jobs.\n */\npackage org.springframework.cloud.task.batch.autoconfigure.kafka;\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration classes for Spring Cloud Task single-step batch jobs.\n */\npackage org.springframework.cloud.task.batch.autoconfigure;\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/rabbit/AmqpItemReaderAutoConfiguration.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.rabbit;\n\nimport java.util.Map;\n\nimport org.springframework.amqp.core.AmqpTemplate;\nimport org.springframework.amqp.support.converter.JacksonJsonMessageConverter;\nimport org.springframework.amqp.support.converter.MessageConverter;\nimport org.springframework.batch.infrastructure.item.amqp.AmqpItemReader;\nimport org.springframework.batch.infrastructure.item.amqp.builder.AmqpItemReaderBuilder;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.amqp.autoconfigure.RabbitProperties;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Autconfiguration for a {@code AmqpItemReader}.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @since 2.3\n */\n@AutoConfiguration\n@EnableConfigurationProperties(AmqpItemReaderProperties.class)\n@AutoConfigureAfter(BatchAutoConfiguration.class)\n@ConditionalOnProperty(name = \"spring.batch.job.amqpitemreader.enabled\", havingValue = \"true\", matchIfMissing = false)\npublic class AmqpItemReaderAutoConfiguration {\n\n\t@Autowired(required = false)\n\tprivate RabbitProperties rabbitProperties;\n\n\t@Bean\n\tpublic AmqpItemReaderProperties amqpItemReaderProperties() {\n\t\treturn new AmqpItemReaderProperties();\n\t}\n\n\t@Bean\n\tpublic AmqpItemReader<Map<String, Object>> amqpItemReader(AmqpTemplate amqpTemplate,\n\t\t\t@Autowired(required = false) Class itemType) {\n\t\tAmqpItemReaderBuilder<Map<String, Object>> builder = new AmqpItemReaderBuilder<Map<String, Object>>()\n\t\t\t.amqpTemplate(amqpTemplate);\n\t\tif (itemType != null) {\n\t\t\tbuilder.itemType(itemType);\n\t\t}\n\t\treturn builder.build();\n\t}\n\n\t@ConditionalOnProperty(name = \"spring.batch.job.amqpitemreader.jsonConverterEnabled\", havingValue = \"true\",\n\t\t\tmatchIfMissing = true)\n\t@Bean\n\tpublic MessageConverter messageConverter() {\n\t\treturn new JacksonJsonMessageConverter();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/rabbit/AmqpItemReaderProperties.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.rabbit;\n\nimport org.springframework.amqp.support.converter.JacksonJsonMessageConverter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Properties to configure a {@code AmqpItemReader}.\n *\n * @author Glenn Renfro\n * @since 2.3\n */\n@ConfigurationProperties(prefix = \"spring.batch.job.amqpitemreader\")\npublic class AmqpItemReaderProperties {\n\n\t/**\n\t * Enables or disables the {@code AmqpItemReader}. Defaults to {@code false}.\n\t */\n\tprivate boolean enabled;\n\n\t/**\n\t * Establishes whether the {@link JacksonJsonMessageConverter} is to be used as a\n\t * message converter. Defaults to {@code true}.\n\t */\n\tprivate boolean jsonConverterEnabled = true;\n\n\t/**\n\t * The state of the enabled flag.\n\t * @return true if AmqpItemReader is enabled. Otherwise false.\n\t */\n\tpublic boolean isEnabled() {\n\t\treturn enabled;\n\t}\n\n\t/**\n\t * Enables or disables the AmqpItemReader.\n\t * @param enabled if true then AmqpItemReader will be enabled. Defaults to false.\n\t */\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\t/**\n\t * States whether the {@link JacksonJsonMessageConverter} is used as a message\n\t * converter.\n\t * @return true if enabled else false.\n\t */\n\tpublic boolean isJsonConverterEnabled() {\n\t\treturn jsonConverterEnabled;\n\t}\n\n\t/**\n\t * Establishes whether the {@link JacksonJsonMessageConverter} is to be used as a\n\t * message converter.\n\t * @param jsonConverterEnabled true if it is to be enabled else false. Defaults to\n\t * true.\n\t */\n\tpublic void setJsonConverterEnabled(boolean jsonConverterEnabled) {\n\t\tthis.jsonConverterEnabled = jsonConverterEnabled;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/rabbit/AmqpItemWriterAutoConfiguration.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.rabbit;\n\nimport java.util.Map;\n\nimport org.springframework.amqp.core.AmqpTemplate;\nimport org.springframework.amqp.support.converter.JacksonJsonMessageConverter;\nimport org.springframework.amqp.support.converter.MessageConverter;\nimport org.springframework.batch.infrastructure.item.amqp.AmqpItemWriter;\nimport org.springframework.batch.infrastructure.item.amqp.builder.AmqpItemWriterBuilder;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Autconfiguration for a {@code AmqpItemWriter}.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @since 2.3\n */\n@AutoConfiguration\n@EnableConfigurationProperties(AmqpItemWriterProperties.class)\n@AutoConfigureAfter(BatchAutoConfiguration.class)\n@ConditionalOnProperty(name = \"spring.batch.job.amqpitemwriter.enabled\", havingValue = \"true\", matchIfMissing = false)\npublic class AmqpItemWriterAutoConfiguration {\n\n\t@Bean\n\tpublic AmqpItemWriter<Map<String, Object>> amqpItemWriter(AmqpTemplate amqpTemplate) {\n\t\treturn new AmqpItemWriterBuilder<Map<String, Object>>().amqpTemplate(amqpTemplate).build();\n\t}\n\n\t@Bean\n\tpublic AmqpItemWriterProperties amqpItemWriterProperties() {\n\t\treturn new AmqpItemWriterProperties();\n\t}\n\n\t@ConditionalOnProperty(name = \"spring.batch.job.amqpitemwriter.jsonConverterEnabled\", havingValue = \"true\",\n\t\t\tmatchIfMissing = true)\n\t@Bean\n\tpublic MessageConverter messageConverter() {\n\t\treturn new JacksonJsonMessageConverter();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/rabbit/AmqpItemWriterProperties.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.rabbit;\n\nimport org.springframework.amqp.support.converter.JacksonJsonMessageConverter;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * @author Glenn Renfro\n * @since 2.3\n */\n@ConfigurationProperties(prefix = \"spring.batch.job.amqpitemwriter\")\npublic class AmqpItemWriterProperties {\n\n\t/**\n\t * Enables or disables the AmqpItemWriter. Defaults to {@code false}.\n\t */\n\tprivate boolean enabled;\n\n\t/**\n\t * Establishes whether the {@link JacksonJsonMessageConverter} is to be used as a\n\t * message converter. Defaults to {@code true}.\n\t */\n\tprivate boolean jsonConverterEnabled = true;\n\n\t/**\n\t * The state of the enabled flag.\n\t * @return {@code true} if {@code AmqpItemWriter} is enabled. Otherwise {@code false}.\n\t */\n\tpublic boolean isEnabled() {\n\t\treturn enabled;\n\t}\n\n\t/**\n\t * Enables or disables the {@code AmqpItemWriter}.\n\t * @param enabled if {@code true} then {@code AmqpItemWriter} is enabled. Defaults to\n\t * {@code false}.\n\t */\n\tpublic void setEnabled(boolean enabled) {\n\t\tthis.enabled = enabled;\n\t}\n\n\t/**\n\t * States whether the {@link JacksonJsonMessageConverter} is used as a message\n\t * converter.\n\t * @return true if enabled else false.\n\t */\n\tpublic boolean isJsonConverterEnabled() {\n\t\treturn jsonConverterEnabled;\n\t}\n\n\t/**\n\t * Establishes whether the {@link JacksonJsonMessageConverter} is to be used as a\n\t * message converter.\n\t * @param jsonConverterEnabled true if it is to be enabled else false. Defaults to\n\t * true.\n\t */\n\tpublic void setJsonConverterEnabled(boolean jsonConverterEnabled) {\n\t\tthis.jsonConverterEnabled = jsonConverterEnabled;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/java/org/springframework/cloud/task/batch/autoconfigure/rabbit/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Auto-configuration classes for RabbitMQ item readers and writers in single-step batch\n * jobs.\n */\npackage org.springframework.cloud.task.batch.autoconfigure.rabbit;\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderAutoConfiguration\norg.springframework.cloud.task.batch.autoconfigure.RangeConverter\norg.springframework.cloud.task.batch.autoconfigure.SingleStepJobAutoConfiguration\norg.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterAutoConfiguration\norg.springframework.cloud.task.batch.autoconfigure.jdbc.JdbcBatchItemWriterAutoConfiguration\norg.springframework.cloud.task.batch.autoconfigure.jdbc.JdbcCursorItemReaderAutoConfiguration\norg.springframework.cloud.task.batch.autoconfigure.rabbit.AmqpItemReaderAutoConfiguration\norg.springframework.cloud.task.batch.autoconfigure.rabbit.AmqpItemWriterAutoConfiguration\norg.springframework.cloud.task.batch.autoconfigure.kafka.KafkaItemReaderAutoConfiguration\norg.springframework.cloud.task.batch.autoconfigure.kafka.KafkaItemWriterAutoConfiguration\n\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/main/resources/META-INF/spring-configuration-metadata.json",
    "content": "{\n\t\"groups\": [\n\t\t{\n\t\t\t\"name\": \"spring.batch.job\",\n\t\t\t\"type\": \"org.springframework.cloud.task.batch.autoconfigure.SingleStepJobProperties\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.SingleStepJobProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader\",\n\t\t\t\"type\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter\",\n\t\t\t\"type\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\"\n\t\t}\n\t],\n\t\"properties\": [\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.chunk-size\",\n\t\t\t\"type\": \"java.lang.Integer\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.SingleStepJobProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.comments\",\n\t\t\t\"type\": \"java.util.List<java.lang.String>\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.current-item-count\",\n\t\t\t\"type\": \"java.lang.Integer\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\",\n\t\t\t\"defaultValue\": 0\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.delimited\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\",\n\t\t\t\"defaultValue\": false\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.delimiter\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.encoding\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.fixed-length\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\",\n\t\t\t\"defaultValue\": false\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.included-fields\",\n\t\t\t\"type\": \"java.util.List<java.lang.Integer>\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.lines-to-skip\",\n\t\t\t\"type\": \"java.lang.Integer\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\",\n\t\t\t\"defaultValue\": 0\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.max-item-count\",\n\t\t\t\"type\": \"java.lang.Integer\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.name\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.names\",\n\t\t\t\"type\": \"java.lang.String[]\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.parsing-strict\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\",\n\t\t\t\"defaultValue\": true\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.quote-character\",\n\t\t\t\"type\": \"java.lang.Character\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.ranges\",\n\t\t\t\"type\": \"java.util.List<org.springframework.batch.infrastructure.item.file.transform.Range>\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.resource\",\n\t\t\t\"type\": \"org.springframework.core.io.Resource\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.save-state\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\",\n\t\t\t\"defaultValue\": true\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilereader.strict\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemReaderProperties\",\n\t\t\t\"defaultValue\": true\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.append\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"defaultValue\": false\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.delimited\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"defaultValue\": false\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.delimiter\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"defaultValue\": \",\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.encoding\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.force-sync\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"defaultValue\": false\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.format\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.formatted\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"defaultValue\": false\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.line-separator\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.locale\",\n\t\t\t\"type\": \"java.util.Locale\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.maximum-length\",\n\t\t\t\"type\": \"java.lang.Integer\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"defaultValue\": 0\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.minimum-length\",\n\t\t\t\"type\": \"java.lang.Integer\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"defaultValue\": 0\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.name\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.names\",\n\t\t\t\"type\": \"java.lang.String[]\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.resource\",\n\t\t\t\"type\": \"org.springframework.core.io.Resource\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.save-state\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"defaultValue\": true\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.should-delete-if-empty\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"defaultValue\": false\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.should-delete-if-exists\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\",\n\t\t\t\"defaultValue\": true\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.flatfilewriter.transactional\",\n\t\t\t\"type\": \"java.lang.Boolean\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.flatfile.FlatFileItemWriterProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.job-name\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.SingleStepJobProperties\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"spring.batch.job.step-name\",\n\t\t\t\"type\": \"java.lang.String\",\n\t\t\t\"sourceType\": \"org.springframework.cloud.task.batch.autoconfigure.SingleStepJobProperties\"\n\t\t}\n\t],\n\t\"hints\": []\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/RangeConverterTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.infrastructure.item.file.transform.Range;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * @author Michael Minella\n */\npublic class RangeConverterTests {\n\n\t@Test\n\tpublic void testNullInput() {\n\t\tRangeConverter converter = new RangeConverter();\n\n\t\tassertThat(converter.convert(null)).isNull();\n\t}\n\n\t@Test\n\tpublic void testStartValueOnly() {\n\t\tRangeConverter converter = new RangeConverter();\n\n\t\tRange range = converter.convert(\"5\");\n\n\t\tassertThat(range.getMin()).isEqualTo(5);\n\t\tassertThat(range.getMax()).isEqualTo(Integer.MAX_VALUE);\n\t}\n\n\t@Test\n\tpublic void testStartAndEndValue() {\n\t\tRangeConverter converter = new RangeConverter();\n\n\t\tRange range = converter.convert(\"5-25\");\n\n\t\tassertThat(range.getMin()).isEqualTo(5);\n\t\tassertThat(range.getMax()).isEqualTo(25);\n\t}\n\n\t@Test\n\tpublic void testIllegalValue() {\n\t\tRangeConverter converter = new RangeConverter();\n\n\t\tassertThatExceptionOfType(NumberFormatException.class).isThrownBy(() -> {\n\t\t\tconverter.convert(\"invalid\");\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testTooManyValues() {\n\t\tRangeConverter converter = new RangeConverter();\n\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tconverter.convert(\"1-2-3-4\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/SingleStepJobAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.infrastructure.item.support.ListItemReader;\nimport org.springframework.batch.infrastructure.item.support.ListItemWriter;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * @author Michael Minella\n */\npublic class SingleStepJobAutoConfigurationTests {\n\n\t@Test\n\tpublic void testInvalidProperties() {\n\t\tSingleStepJobProperties properties = new SingleStepJobProperties();\n\n\t\ttry {\n\t\t\tnew SingleStepJobAutoConfiguration(properties, null);\n\t\t}\n\t\tcatch (IllegalArgumentException iae) {\n\t\t\tassertThat(iae.getMessage()).isEqualTo(\"A job name is required\");\n\t\t}\n\t\tcatch (Throwable t) {\n\t\t\tfail(\"wrong exception was thrown\", t);\n\t\t}\n\n\t\tproperties.setJobName(\"job\");\n\n\t\ttry {\n\t\t\tnew SingleStepJobAutoConfiguration(properties, null);\n\t\t}\n\t\tcatch (IllegalArgumentException iae) {\n\t\t\tassertThat(iae.getMessage()).isEqualTo(\"A step name is required\");\n\t\t}\n\t\tcatch (Throwable t) {\n\t\t\tfail(\"wrong exception was thrown\", t);\n\t\t}\n\n\t\tproperties.setStepName(\"step\");\n\n\t\ttry {\n\t\t\tnew SingleStepJobAutoConfiguration(properties, null);\n\t\t}\n\t\tcatch (IllegalArgumentException iae) {\n\t\t\tassertThat(iae.getMessage()).isEqualTo(\"A chunk size is required\");\n\t\t}\n\t\tcatch (Throwable t) {\n\t\t\tfail(\"wrong exception was thrown\", t);\n\t\t}\n\n\t\tproperties.setChunkSize(-5);\n\n\t\ttry {\n\t\t\tnew SingleStepJobAutoConfiguration(properties, null);\n\t\t}\n\t\tcatch (IllegalArgumentException iae) {\n\t\t\tassertThat(iae.getMessage()).isEqualTo(\"A chunk size greater than zero is required\");\n\t\t}\n\t\tcatch (Throwable t) {\n\t\t\tfail(\"wrong exception was thrown\", t);\n\t\t}\n\n\t\tproperties.setChunkSize(5);\n\t}\n\n\t@Test\n\tpublic void testSimpleConfiguration() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(SimpleConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\");\n\n\t\tvalidateConfiguration(applicationContextRunner);\n\t}\n\n\t@Test\n\tpublic void testSimpleConfigurationKabobStyle() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(SimpleConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.job-name=job\", \"spring.batch.job.step-name=step1\",\n\t\t\t\t\t\"spring.batch.job.chunk-size=5\");\n\n\t\tvalidateConfiguration(applicationContextRunner);\n\t}\n\n\tprivate void validateConfiguration(ApplicationContextRunner applicationContextRunner) {\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tListItemWriter itemWriter = context.getBean(ListItemWriter.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tList<Map<String, Object>> writtenItems = itemWriter.getWrittenItems();\n\n\t\t\tassertThat(writtenItems.size()).isEqualTo(3);\n\n\t\t\tassertThat(writtenItems.get(0).get(\"item\")).isEqualTo(\"foo\");\n\t\t\tassertThat(writtenItems.get(1).get(\"item\")).isEqualTo(\"bar\");\n\t\t\tassertThat(writtenItems.get(2).get(\"item\")).isEqualTo(\"baz\");\n\t\t});\n\t}\n\n\t@Configuration\n\tpublic static class SimpleConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemReader<Map<String, Object>> itemReader() {\n\t\t\tList<Map<String, Object>> items = new ArrayList<>(3);\n\n\t\t\titems.add(Collections.singletonMap(\"item\", \"foo\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"bar\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"baz\"));\n\n\t\t\treturn new ListItemReader<>(items);\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemWriter<Map<String, Object>> itemWriter() {\n\t\t\treturn new ListItemWriter<>();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/flatfile/FlatFileItemReaderAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.flatfile;\n\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.infrastructure.item.file.LineCallbackHandler;\nimport org.springframework.batch.infrastructure.item.file.LineMapper;\nimport org.springframework.batch.infrastructure.item.file.mapping.FieldSetMapper;\nimport org.springframework.batch.infrastructure.item.file.separator.RecordSeparatorPolicy;\nimport org.springframework.batch.infrastructure.item.file.transform.DefaultFieldSet;\nimport org.springframework.batch.infrastructure.item.file.transform.LineTokenizer;\nimport org.springframework.batch.infrastructure.item.support.ListItemWriter;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.batch.autoconfigure.RangeConverter;\nimport org.springframework.cloud.task.batch.autoconfigure.SingleStepJobAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Michael Minella\n * @author Glenn Renfro\n */\npublic class FlatFileItemReaderAutoConfigurationTests {\n\n\t/**\n\t * Contents of the file to be read (included here because it's UTF-16).\n\t *\n\t * <pre>\n\t * 1@2@3@4@5@six\n\t * # This should be ignored\n\t * 7@8@9@10@11@twelve\n\t * $ So should this\n\t * 13@14@15@16@17@eighteen\n\t * 19@20@21@22@23@%twenty four%\n\t * 15@26@27@28@29@thirty\n\t * 31@32@33@34@35@thirty six\n\t * 37@38@39@40@41@forty two\n\t * 43@44@45@46@47@forty eight\n\t * 49@50@51@52@53@fifty four\n\t * 55@56@57@58@59@sixty\n\t * </pre>\n\t */\n\t@Test\n\tpublic void testFullDelimitedConfiguration() {\n\t\tBigInteger tokenizerValidator = BigInteger.ZERO;\n\t\ttokenizerValidator = tokenizerValidator.flipBit(0);\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(JobConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemReaderAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.flatfileitemreader.savestate=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.name=fullDelimitedConfiguration\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.maxItemCount=5\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.currentItemCount=2\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.comments=#,$\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.resource=/testUTF16.csv\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.strict=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.encoding=UTF-16\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.linesToSkip=1\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.delimited=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.delimiter=@\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.quoteCharacter=%\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.includedFields=1,3,5\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.names=foo,bar,baz\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.parsingStrict=false\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tListItemWriter itemWriter = context.getBean(ListItemWriter.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tList writtenItems = itemWriter.getWrittenItems();\n\n\t\t\tassertThat(writtenItems.size()).isEqualTo(3);\n\t\t\tassertThat(((Map) writtenItems.get(0)).get(\"foo\")).isEqualTo(\"20\");\n\t\t\tassertThat(((Map) writtenItems.get(0)).get(\"bar\")).isEqualTo(\"22\");\n\t\t\tassertThat(((Map) writtenItems.get(0)).get(\"baz\")).isEqualTo(\"twenty four\");\n\t\t\tassertThat(((Map) writtenItems.get(1)).get(\"foo\")).isEqualTo(\"26\");\n\t\t\tassertThat(((Map) writtenItems.get(1)).get(\"bar\")).isEqualTo(\"28\");\n\t\t\tassertThat(((Map) writtenItems.get(1)).get(\"baz\")).isEqualTo(\"thirty\");\n\t\t\tassertThat(((Map) writtenItems.get(2)).get(\"foo\")).isEqualTo(\"32\");\n\t\t\tassertThat(((Map) writtenItems.get(2)).get(\"bar\")).isEqualTo(\"34\");\n\t\t\tassertThat(((Map) writtenItems.get(2)).get(\"baz\")).isEqualTo(\"thirty six\");\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testFixedWidthConfiguration() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(JobConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemReaderAutoConfiguration.class, RangeConverter.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.flatfileitemreader.savestate=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.name=fixedWidthConfiguration\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.comments=#,$\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.resource=/test.txt\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.strict=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.fixedLength=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.ranges=3-4,7-8,11\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.names=foo,bar,baz\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.parsingStrict=false\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tListItemWriter itemWriter = context.getBean(ListItemWriter.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tList writtenItems = itemWriter.getWrittenItems();\n\n\t\t\tassertThat(writtenItems.size()).isEqualTo(6);\n\t\t\tassertThat(((Map) writtenItems.get(0)).get(\"foo\")).isEqualTo(\"2\");\n\t\t\tassertThat(((Map) writtenItems.get(0)).get(\"bar\")).isEqualTo(\"4\");\n\t\t\tassertThat(((Map) writtenItems.get(0)).get(\"baz\")).isEqualTo(\"six\");\n\t\t\tassertThat(((Map) writtenItems.get(1)).get(\"foo\")).isEqualTo(\"8\");\n\t\t\tassertThat(((Map) writtenItems.get(1)).get(\"bar\")).isEqualTo(\"10\");\n\t\t\tassertThat(((Map) writtenItems.get(1)).get(\"baz\")).isEqualTo(\"twelve\");\n\t\t\tassertThat(((Map) writtenItems.get(2)).get(\"foo\")).isEqualTo(\"14\");\n\t\t\tassertThat(((Map) writtenItems.get(2)).get(\"bar\")).isEqualTo(\"16\");\n\t\t\tassertThat(((Map) writtenItems.get(2)).get(\"baz\")).isEqualTo(\"eighteen\");\n\t\t\tassertThat(((Map) writtenItems.get(3)).get(\"foo\")).isEqualTo(\"20\");\n\t\t\tassertThat(((Map) writtenItems.get(3)).get(\"bar\")).isEqualTo(\"22\");\n\t\t\tassertThat(((Map) writtenItems.get(3)).get(\"baz\")).isEqualTo(\"twenty four\");\n\t\t\tassertThat(((Map) writtenItems.get(4)).get(\"foo\")).isEqualTo(\"26\");\n\t\t\tassertThat(((Map) writtenItems.get(4)).get(\"bar\")).isEqualTo(\"28\");\n\t\t\tassertThat(((Map) writtenItems.get(4)).get(\"baz\")).isEqualTo(\"thirty\");\n\t\t\tassertThat(((Map) writtenItems.get(5)).get(\"foo\")).isEqualTo(\"32\");\n\t\t\tassertThat(((Map) writtenItems.get(5)).get(\"bar\")).isEqualTo(\"34\");\n\t\t\tassertThat(((Map) writtenItems.get(5)).get(\"baz\")).isEqualTo(\"thirty six\");\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testCustomLineMapper() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(CustomLineMapperConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemReaderAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.flatfileitemreader.name=fixedWidthConfiguration\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.resource=/test.txt\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.strict=true\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tListItemWriter itemWriter = context.getBean(ListItemWriter.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tList writtenItems = itemWriter.getWrittenItems();\n\n\t\t\tassertThat(writtenItems.size()).isEqualTo(8);\n\t\t});\n\t}\n\n\t/**\n\t * This test requires an input file with an even number of records.\n\t */\n\t@Test\n\tpublic void testCustomRecordSeparatorAndSkippedLines() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(RecordSeparatorAndSkippedLinesJobConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemReaderAutoConfiguration.class, RangeConverter.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.flatfileitemreader.name=fixedWidthConfiguration\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.resource=/test.txt\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.linesToSkip=2\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.fixedLength=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.ranges=3-4,7-8,11\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.names=foo,bar,baz\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.strict=true\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tListItemWriter itemWriter = context.getBean(ListItemWriter.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tListLineCallbackHandler callbackHandler = context.getBean(ListLineCallbackHandler.class);\n\n\t\t\tassertThat(callbackHandler.getLines().size()).isEqualTo(2);\n\n\t\t\tList writtenItems = itemWriter.getWrittenItems();\n\n\t\t\tassertThat(writtenItems.size()).isEqualTo(2);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testCustomMapping() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(CustomMappingConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemReaderAutoConfiguration.class, RangeConverter.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.flatfileitemreader.name=fixedWidthConfiguration\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.resource=/test.txt\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.maxItemCount=1\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemreader.strict=true\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tListItemWriter itemWriter = context.getBean(ListItemWriter.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tList<Map<String, Object>> writtenItems = itemWriter.getWrittenItems();\n\n\t\t\tassertThat(writtenItems.size()).isEqualTo(1);\n\t\t\tassertThat(writtenItems.get(0).get(\"one\")).isEqualTo(\"1 2 3\");\n\t\t\tassertThat(writtenItems.get(0).get(\"two\")).isEqualTo(\"4 5 six\");\n\t\t});\n\t}\n\n\t@Configuration\n\tpublic static class CustomMappingConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemWriter<Map<String, Object>> itemWriter() {\n\t\t\treturn new ListItemWriter<>();\n\t\t}\n\n\t\t@Bean\n\t\tpublic LineTokenizer lineTokenizer() {\n\t\t\treturn line -> new DefaultFieldSet(new String[] { line.substring(0, 5), line.substring(6) },\n\t\t\t\t\tnew String[] { \"one\", \"two\" });\n\t\t}\n\n\t\t@Bean\n\t\tpublic FieldSetMapper<Map<String, Object>> fieldSetMapper() {\n\t\t\treturn fieldSet -> new HashMap<String, Object>((Map) fieldSet.getProperties());\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class JobConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemWriter<Map<String, Object>> itemWriter() {\n\t\t\treturn new ListItemWriter<>();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class RecordSeparatorAndSkippedLinesJobConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic RecordSeparatorPolicy recordSeparatorPolicy() {\n\t\t\treturn new RecordSeparatorPolicy() {\n\t\t\t\t@Override\n\t\t\t\tpublic boolean isEndOfRecord(String record) {\n\n\t\t\t\t\tboolean endOfRecord = false;\n\n\t\t\t\t\tint index = record.indexOf('\\n');\n\n\t\t\t\t\tif (index > 0 && record.length() > index + 1) {\n\t\t\t\t\t\tendOfRecord = true;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn endOfRecord;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String postProcess(String record) {\n\t\t\t\t\treturn record;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic String preProcess(String record) {\n\t\t\t\t\treturn record + '\\n';\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tpublic LineCallbackHandler lineCallbackHandler() {\n\t\t\treturn new ListLineCallbackHandler();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemWriter<Map<String, Object>> itemWriter() {\n\t\t\treturn new ListItemWriter<>();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class CustomLineMapperConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic LineMapper<Map<String, Object>> lineMapper() {\n\t\t\treturn (line, lineNumber) -> {\n\t\t\t\tMap<String, Object> item = new HashMap<>(1);\n\n\t\t\t\titem.put(\"line\", line);\n\t\t\t\titem.put(\"lineNumber\", lineNumber);\n\n\t\t\t\treturn item;\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemWriter<Map<String, Object>> itemWriter() {\n\t\t\treturn new ListItemWriter<>();\n\t\t}\n\n\t}\n\n\tpublic static class ListLineCallbackHandler implements LineCallbackHandler {\n\n\t\tprivate List<String> lines = new ArrayList<>();\n\n\t\t@Override\n\t\tpublic void handleLine(String line) {\n\t\t\tlines.add(line);\n\t\t}\n\n\t\tpublic List<String> getLines() {\n\t\t\treturn lines;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/flatfile/FlatFileItemWriterAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.flatfile;\n\nimport java.io.File;\nimport java.io.InputStreamReader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.assertj.core.api.Assertions;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.infrastructure.item.file.FlatFileFooterCallback;\nimport org.springframework.batch.infrastructure.item.file.FlatFileHeaderCallback;\nimport org.springframework.batch.infrastructure.item.file.FlatFileItemWriter;\nimport org.springframework.batch.infrastructure.item.file.transform.FieldExtractor;\nimport org.springframework.batch.infrastructure.item.file.transform.LineAggregator;\nimport org.springframework.batch.infrastructure.item.file.transform.PassThroughLineAggregator;\nimport org.springframework.batch.infrastructure.item.support.ListItemReader;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.batch.autoconfigure.SingleStepJobAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.util.FileCopyUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * @author Michael Minella\n */\npublic class FlatFileItemWriterAutoConfigurationTests {\n\n\tprivate File outputFile;\n\n\t@BeforeEach\n\tpublic void setUp() throws Exception {\n\t\tthis.outputFile = File.createTempFile(\"flatfile-config-test-output\", \".tmp\");\n\t}\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tthis.outputFile.delete();\n\t}\n\n\t@Test\n\tpublic void testValidation() {\n\n\t\tFlatFileItemWriterProperties properties = new FlatFileItemWriterProperties();\n\n\t\tproperties.setFormatted(true);\n\t\tproperties.setDelimited(true);\n\n\t\tFlatFileItemWriterAutoConfiguration configuration = new FlatFileItemWriterAutoConfiguration(properties);\n\n\t\ttry {\n\t\t\tconfiguration.itemWriter();\n\t\t\tfail(\"Exception should have been thrown when both formatted and delimited are selected\");\n\t\t}\n\t\tcatch (IllegalStateException ise) {\n\t\t\tassertThat(ise.getMessage()).isEqualTo(\"An output file must be either delimited or formatted or a custom \"\n\t\t\t\t\t+ \"LineAggregator must be provided. Your current configuration specifies both delimited and formatted\");\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tfail(\"Incorrect exception thrown\", e);\n\t\t}\n\n\t\tproperties.setFormatted(true);\n\t\tproperties.setDelimited(false);\n\n\t\tReflectionTestUtils.setField(configuration, \"lineAggregator\", new PassThroughLineAggregator<>());\n\n\t\ttry {\n\t\t\tconfiguration.itemWriter();\n\t\t\tfail(\"Exception should have been thrown when a LineAggregator and one of the autocreated options are selected\");\n\t\t}\n\t\tcatch (IllegalStateException ise) {\n\t\t\tassertThat(ise.getMessage())\n\t\t\t\t.isEqualTo(\"A LineAggregator must be configured if the \" + \"output is not formatted or delimited\");\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tfail(\"Incorrect exception thrown\", e);\n\t\t}\n\n\t\tproperties.setFormatted(false);\n\t\tproperties.setDelimited(true);\n\n\t\ttry {\n\t\t\tconfiguration.itemWriter();\n\t\t\tfail(\"Exception should have been thrown when a LineAggregator and one of the autocreated options are selected\");\n\t\t}\n\t\tcatch (IllegalStateException ise) {\n\t\t\tassertThat(ise.getMessage())\n\t\t\t\t.isEqualTo(\"A LineAggregator must be configured if the \" + \"output is not formatted or delimited\");\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tfail(\"Incorrect exception thrown\", e);\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testDelimitedFileGeneration() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(DelimitedJobConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemWriterAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.flatfileitemwriter.name=fooWriter\",\n\t\t\t\t\tString.format(\"spring.batch.job.flatfileitemwriter.resource=file://%s\",\n\t\t\t\t\t\t\tthis.outputFile.getAbsolutePath()),\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.encoding=UTF-16\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.saveState=false\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.shouldDeleteIfEmpty=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.delimited=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.names=item\", \"spring.batch.job.flatfileitemwriter.append=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.forceSync=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.shouldDeleteIfExists=false\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.transactional=false\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tFlatFileItemWriter writer = context.getBean(FlatFileItemWriter.class);\n\n\t\t\tassertThat(Assertions.linesOf(this.outputFile, StandardCharsets.UTF_16).size()).isEqualTo(3);\n\t\t\tassertThat(Assertions.contentOf((new ClassPathResource(\"writerTestUTF16.txt\")).getFile())\n\t\t\t\t.equals(new FileSystemResource(this.outputFile)));\n\n\t\t\tassertThat((Boolean) ReflectionTestUtils.getField(writer, \"saveState\")).isFalse();\n\t\t\tassertThat((Boolean) ReflectionTestUtils.getField(writer, \"append\")).isTrue();\n\t\t\tassertThat((Boolean) ReflectionTestUtils.getField(writer, \"forceSync\")).isTrue();\n\t\t\tassertThat((Boolean) ReflectionTestUtils.getField(writer, \"shouldDeleteIfExists\")).isFalse();\n\t\t\tassertThat((Boolean) ReflectionTestUtils.getField(writer, \"transactional\")).isFalse();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testFormattedFileGeneration() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(FormattedJobConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemWriterAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=2\", \"spring.batch.job.flatfileitemwriter.name=fooWriter\",\n\t\t\t\t\tString.format(\"spring.batch.job.flatfileitemwriter.resource=file://%s\",\n\t\t\t\t\t\t\tthis.outputFile.getAbsolutePath()),\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.encoding=UTF-8\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.formatted=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.names=item\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.format=item = %s\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.minimumLength=8\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.maximumLength=10\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tassertThat(Assertions.linesOf(this.outputFile).size()).isEqualTo(2);\n\n\t\t\tString results = FileCopyUtils\n\t\t\t\t.copyToString(new InputStreamReader(new FileSystemResource(this.outputFile).getInputStream()));\n\t\t\tassertThat(results).isEqualTo(\"item = foo\\nitem = bar\\n\");\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testFormattedFieldExtractorFileGeneration() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(FormattedFieldExtractorJobConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemWriterAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.flatfileitemwriter.name=fooWriter\",\n\t\t\t\t\tString.format(\"spring.batch.job.flatfileitemwriter.resource=file://%s\",\n\t\t\t\t\t\t\tthis.outputFile.getAbsolutePath()),\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.encoding=UTF-8\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.formatted=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.names=item\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.format=item = %s\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tassertThat(Assertions.linesOf(this.outputFile).size()).isEqualTo(3);\n\n\t\t\tString results = FileCopyUtils\n\t\t\t\t.copyToString(new InputStreamReader(new FileSystemResource(this.outputFile).getInputStream()));\n\t\t\tassertThat(results).isEqualTo(\"item = f\\nitem = b\\nitem = b\\n\");\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testFieldExtractorFileGeneration() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(FieldExtractorConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemWriterAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.flatfileitemwriter.name=fooWriter\",\n\t\t\t\t\tString.format(\"spring.batch.job.flatfileitemwriter.resource=file://%s\",\n\t\t\t\t\t\t\tthis.outputFile.getAbsolutePath()),\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.encoding=UTF-8\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.delimited=true\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tassertThat(Assertions.linesOf(this.outputFile, StandardCharsets.UTF_8).size()).isEqualTo(3);\n\n\t\t\tString results = FileCopyUtils\n\t\t\t\t.copyToString(new InputStreamReader(new FileSystemResource(this.outputFile).getInputStream()));\n\t\t\tassertThat(results).isEqualTo(\"f\\nb\\nb\\n\");\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testCustomLineAggregatorFileGeneration() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(LineAggregatorConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemWriterAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.flatfileitemwriter.name=fooWriter\",\n\t\t\t\t\tString.format(\"spring.batch.job.flatfileitemwriter.resource=file://%s\",\n\t\t\t\t\t\t\tthis.outputFile.getAbsolutePath()),\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.encoding=UTF-8\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tassertThat(Assertions.linesOf(this.outputFile, StandardCharsets.UTF_8).size()).isEqualTo(3);\n\n\t\t\tString results = FileCopyUtils\n\t\t\t\t.copyToString(new InputStreamReader(new FileSystemResource(this.outputFile).getInputStream()));\n\t\t\tassertThat(results).isEqualTo(\"{item=foo}\\n{item=bar}\\n{item=baz}\\n\");\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testHeaderFooterFileGeneration() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(HeaderFooterConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tFlatFileItemWriterAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.flatfileitemwriter.name=fooWriter\",\n\t\t\t\t\tString.format(\"spring.batch.job.flatfileitemwriter.resource=file://%s\",\n\t\t\t\t\t\t\tthis.outputFile.getAbsolutePath()),\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.encoding=UTF-8\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.delimited=true\",\n\t\t\t\t\t\"spring.batch.job.flatfileitemwriter.names=item\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tassertThat(Assertions.linesOf(this.outputFile, StandardCharsets.UTF_8).size()).isEqualTo(5);\n\n\t\t\tString results = FileCopyUtils\n\t\t\t\t.copyToString(new InputStreamReader(new FileSystemResource(this.outputFile).getInputStream()));\n\t\t\tassertThat(results).isEqualTo(\"header\\nfoo\\nbar\\nbaz\\nfooter\");\n\t\t});\n\t}\n\n\t@Configuration\n\tpublic static class DelimitedJobConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemReader<Map<String, Object>> itemReader() {\n\n\t\t\tList<Map<String, Object>> items = new ArrayList<>(3);\n\n\t\t\titems.add(Collections.singletonMap(\"item\", \"foo\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"bar\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"baz\"));\n\n\t\t\treturn new ListItemReader<>(items);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class LineAggregatorConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemReader<Map<String, Object>> itemReader() {\n\n\t\t\tList<Map<String, Object>> items = new ArrayList<>(3);\n\n\t\t\titems.add(Collections.singletonMap(\"item\", \"foo\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"bar\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"baz\"));\n\n\t\t\treturn new ListItemReader<>(items);\n\t\t}\n\n\t\t@Bean\n\t\tpublic LineAggregator<Map<String, Object>> lineAggregator() {\n\t\t\treturn new PassThroughLineAggregator<>();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class HeaderFooterConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemReader<Map<String, Object>> itemReader() {\n\n\t\t\tList<Map<String, Object>> items = new ArrayList<>(3);\n\n\t\t\titems.add(Collections.singletonMap(\"item\", \"foo\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"bar\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"baz\"));\n\n\t\t\treturn new ListItemReader<>(items);\n\t\t}\n\n\t\t@Bean\n\t\tpublic FlatFileHeaderCallback headerCallback() {\n\t\t\treturn writer -> writer.append(\"header\");\n\t\t}\n\n\t\t@Bean\n\t\tpublic FlatFileFooterCallback footerCallback() {\n\t\t\treturn writer -> writer.append(\"footer\");\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class FieldExtractorConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemReader<Map<String, Object>> itemReader() {\n\n\t\t\tList<Map<String, Object>> items = new ArrayList<>(3);\n\n\t\t\titems.add(Collections.singletonMap(\"item\", \"foo\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"bar\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"baz\"));\n\n\t\t\treturn new ListItemReader<>(items);\n\t\t}\n\n\t\t@Bean\n\t\tpublic FieldExtractor<Map<String, Object>> lineAggregator() {\n\t\t\treturn item -> {\n\t\t\t\tList<String> fields = new ArrayList<>(1);\n\n\t\t\t\tfields.add(((String) item.get(\"item\")).substring(0, 1));\n\t\t\t\treturn fields.toArray();\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class FormattedJobConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemReader<Map<String, Object>> itemReader() {\n\n\t\t\tList<Map<String, Object>> items = new ArrayList<>(3);\n\n\t\t\titems.add(Collections.singletonMap(\"item\", \"foo\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"bar\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"tooLong\"));\n\n\t\t\treturn new ListItemReader<>(items);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class FormattedFieldExtractorJobConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic FieldExtractor<Map<String, Object>> lineAggregator() {\n\t\t\treturn item -> {\n\t\t\t\tList<String> fields = new ArrayList<>(1);\n\n\t\t\t\tfields.add(((String) item.get(\"item\")).substring(0, 1));\n\t\t\t\treturn fields.toArray();\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemReader<Map<String, Object>> itemReader() {\n\n\t\t\tList<Map<String, Object>> items = new ArrayList<>(3);\n\n\t\t\titems.add(Collections.singletonMap(\"item\", \"foo\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"bar\"));\n\t\t\titems.add(Collections.singletonMap(\"item\", \"baz\"));\n\n\t\t\treturn new ListItemReader<>(items);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/jdbc/JdbcBatchItemWriterAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.jdbc;\n\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.h2.tools.Server;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.infrastructure.item.database.ItemPreparedStatementSetter;\nimport org.springframework.batch.infrastructure.item.database.ItemSqlParameterSourceProvider;\nimport org.springframework.batch.infrastructure.item.database.JdbcBatchItemWriter;\nimport org.springframework.batch.infrastructure.item.support.ListItemReader;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.batch.autoconfigure.SingleStepJobAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.jdbc.BadSqlGrammarException;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.SqlTypeValue;\nimport org.springframework.jdbc.core.StatementCreatorUtils;\nimport org.springframework.jdbc.core.namedparam.MapSqlParameterSource;\nimport org.springframework.jdbc.datasource.DriverManagerDataSource;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.test.util.TestSocketUtils;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatThrownBy;\n\npublic class JdbcBatchItemWriterAutoConfigurationTests {\n\n\tprivate final static String DATASOURCE_URL;\n\n\tprivate final static String DATASOURCE_USER_NAME = \"SA\";\n\n\tprivate final static String DATASOURCE_USER_PASSWORD = \"''\";\n\n\tprivate final static String DATASOURCE_DRIVER_CLASS_NAME = \"org.h2.Driver\";\n\n\tprivate static int randomPort;\n\n\tstatic {\n\t\trandomPort = TestSocketUtils.findAvailableTcpPort();\n\t\tDATASOURCE_URL = \"jdbc:h2:tcp://localhost:\" + randomPort + \"/mem:dataflow;DB_CLOSE_DELAY=-1;\"\n\t\t\t\t+ \"DB_CLOSE_ON_EXIT=FALSE\";\n\t}\n\n\t@AfterEach\n\tpublic void clearDB() {\n\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\tdataSource.setDriverClassName(DATASOURCE_DRIVER_CLASS_NAME);\n\t\tdataSource.setUrl(DATASOURCE_URL);\n\t\tdataSource.setUsername(DATASOURCE_USER_NAME);\n\t\tdataSource.setPassword(DATASOURCE_USER_PASSWORD);\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\tjdbcTemplate.execute(\"TRUNCATE TABLE item\");\n\t\ttry {\n\t\t\tjdbcTemplate.execute(\"DELETE FROM BATCH_STEP_EXECUTION_CONTEXT\");\n\t\t\tjdbcTemplate.execute(\"DELETE FROM BATCH_STEP_EXECUTION\");\n\t\t\tjdbcTemplate.execute(\"DELETE FROM BATCH_JOB_EXECUTION_PARAMS\");\n\t\t\tjdbcTemplate.execute(\"DELETE FROM BATCH_JOB_EXECUTION_CONTEXT\");\n\t\t\tjdbcTemplate.execute(\"DELETE FROM BATCH_JOB_EXECUTION\");\n\t\t\tjdbcTemplate.execute(\"DELETE FROM BATCH_JOB_INSTANCE\");\n\t\t}\n\t\tcatch (BadSqlGrammarException e) {\n\t\t\tSystem.out.println(\"No tables to cleanup\");\n\t\t}\n\t}\n\n\t@Test\n\tpublic void baseTest() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskLauncherConfiguration.class,\n\t\t\t\t\tJdbcBatchItemWriterAutoConfigurationTests.DelimitedJobConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, JdbcBatchItemWriterAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jdbcsinglestep.datasource.enable=false\");\n\t\tapplicationContextRunner = updatePropertiesForTest(applicationContextRunner);\n\n\t\trunTest(applicationContextRunner, false);\n\t}\n\n\t@Test\n\tpublic void baseTestWithWriterDataSource() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskLauncherConfiguration.class,\n\t\t\t\t\tJdbcBatchItemWriterAutoConfigurationTests.DelimitedJobConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, JdbcBatchItemWriterAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jdbcbatchitemwriter.datasource.enable=true\",\n\t\t\t\t\t\"spring.batch.job.jdbcsinglestep.datasource.enable=false\", \"spring.batch.job.jobName=job\",\n\t\t\t\t\t\"spring.batch.job.stepName=step1\", \"spring.batch.job.chunkSize=5\",\n\t\t\t\t\t\"spring.batch.job.jdbcbatchitemwriter.name=fooWriter\",\n\t\t\t\t\t\"spring.batch.job.jdbcbatchitemwriter.sql=INSERT INTO item (item_name) VALUES (:item_name)\",\n\t\t\t\t\t\"spring.batch.jdbc.initialize-schema=always\",\n\t\t\t\t\t\"jdbcbatchitemwriter.datasource.url=\" + DATASOURCE_URL,\n\t\t\t\t\t\"jdbcbatchitemwriter.datasource.username=\" + DATASOURCE_USER_NAME,\n\t\t\t\t\t\"jdbcbatchitemwriter.datasource.password=\" + DATASOURCE_USER_PASSWORD,\n\t\t\t\t\t\"jdbcbatchitemwriter.datasource.driverClassName=\" + DATASOURCE_DRIVER_CLASS_NAME);\n\n\t\trunTest(applicationContextRunner, true);\n\t}\n\n\t@Test\n\tpublic void customSqlParameterSourceTest() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskLauncherConfiguration.class,\n\t\t\t\t\tJdbcBatchItemWriterAutoConfigurationTests.DelimitedDifferentKeyNameJobConfiguration.class,\n\t\t\t\t\tCustomSqlParameterSourceProviderConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, JdbcBatchItemWriterAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jdbcsinglestep.datasource.enable=false\");\n\t\tapplicationContextRunner = updatePropertiesForTest(applicationContextRunner);\n\n\t\trunTest(applicationContextRunner, false);\n\t}\n\n\t@Test\n\tpublic void preparedStatementSetterTest() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskLauncherConfiguration.class,\n\t\t\t\t\tJdbcBatchItemWriterAutoConfigurationTests.DelimitedJobConfiguration.class,\n\t\t\t\t\tItemPreparedStatementSetterConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, JdbcBatchItemWriterAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jdbcsinglestep.datasource.enable=false\");\n\t\tapplicationContextRunner = updatePropertiesForTest(applicationContextRunner);\n\t\trunTest(applicationContextRunner, false);\n\t}\n\n\tprivate ApplicationContextRunner updatePropertiesForTest(ApplicationContextRunner applicationContextRunner) {\n\t\treturn applicationContextRunner.withPropertyValues(\"spring.batch.job.jobName=job\",\n\t\t\t\t\"spring.batch.job.stepName=step1\", \"spring.batch.job.chunkSize=5\",\n\t\t\t\t\"spring.batch.job.jdbcbatchitemwriter.name=fooWriter\",\n\t\t\t\t\"spring.batch.job.jdbcbatchitemwriter.sql=INSERT INTO item (item_name) VALUES (:item_name)\",\n\t\t\t\t\"spring.batch.jdbc.initialize-schema=always\");\n\t}\n\n\tprivate void validateResultAndBean(ApplicationContext context, boolean isWriterDataSourcePresent) {\n\t\tDataSource dataSource;\n\t\ttry {\n\t\t\tdataSource = context.getBean(DataSource.class);\n\t\t}\n\t\tcatch (NoSuchBeanDefinitionException nde) {\n\t\t\tdataSource = context.getBean(\"jdbcBatchItemWriterSpringDataSource\", DataSource.class);\n\t\t}\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\tList<Map<String, Object>> result = jdbcTemplate.queryForList(\"SELECT item_name FROM item ORDER BY item_name\");\n\t\tassertThat(result.size()).isEqualTo(3);\n\n\t\tassertThat(result.get(0).get(\"item_name\")).isEqualTo(\"bar\");\n\t\tassertThat(result.get(1).get(\"item_name\")).isEqualTo(\"baz\");\n\t\tassertThat(result.get(2).get(\"item_name\")).isEqualTo(\"foo\");\n\n\t\tJdbcBatchItemWriter writer = context.getBean(JdbcBatchItemWriter.class);\n\t\tassertThat((Boolean) ReflectionTestUtils.getField(writer, \"assertUpdates\")).isTrue();\n\t\tassertThat((Integer) ReflectionTestUtils.getField(writer, \"parameterCount\")).isEqualTo(1);\n\t\tassertThat((Boolean) ReflectionTestUtils.getField(writer, \"usingNamedParameters\")).isTrue();\n\t\tif (!isWriterDataSourcePresent) {\n\t\t\tassertThatThrownBy(() -> context.getBean(\"jdbcBatchItemWriterSpringDataSource\"))\n\t\t\t\t.isInstanceOf(NoSuchBeanDefinitionException.class)\n\t\t\t\t.hasMessageContaining(\"No bean named 'jdbcBatchItemWriterSpringDataSource' available\");\n\t\t}\n\t\telse {\n\t\t\tassertThat(context.getBean(\"jdbcBatchItemWriterSpringDataSource\")).isNotNull();\n\t\t}\n\t}\n\n\tprivate void runTest(ApplicationContextRunner applicationContextRunner, boolean isWriterDataSourcePresent) {\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tvalidateResultAndBean(context, isWriterDataSourcePresent);\n\t\t});\n\t}\n\n\t@Configuration\n\tpublic static class TaskLauncherConfiguration {\n\n\t\tprivate static Server defaultServer;\n\n\t\t@Bean\n\t\tpublic Server initH2TCPServer() {\n\t\t\tServer server = null;\n\t\t\ttry {\n\t\t\t\tif (defaultServer == null) {\n\t\t\t\t\tserver = Server\n\t\t\t\t\t\t.createTcpServer(\"-ifNotExists\", \"-tcp\", \"-tcpAllowOthers\", \"-tcpPort\",\n\t\t\t\t\t\t\t\tString.valueOf(randomPort))\n\t\t\t\t\t\t.start();\n\t\t\t\t\tdefaultServer = server;\n\t\t\t\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\t\t\t\tdataSource.setDriverClassName(DATASOURCE_DRIVER_CLASS_NAME);\n\t\t\t\t\tdataSource.setUrl(DATASOURCE_URL);\n\t\t\t\t\tdataSource.setUsername(DATASOURCE_USER_NAME);\n\t\t\t\t\tdataSource.setPassword(DATASOURCE_USER_PASSWORD);\n\t\t\t\t\tClassPathResource setupResource = new ClassPathResource(\"schema-h2.sql\");\n\t\t\t\t\tResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator(setupResource);\n\t\t\t\t\tresourceDatabasePopulator.execute(dataSource);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (SQLException e) {\n\t\t\t\tthrow new IllegalStateException(e);\n\t\t\t}\n\t\t\treturn defaultServer;\n\t\t}\n\n\t\t@Bean\n\t\tpublic DataSource dataSource(Server server) {\n\t\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\t\tdataSource.setDriverClassName(DATASOURCE_DRIVER_CLASS_NAME);\n\t\t\tdataSource.setUrl(DATASOURCE_URL);\n\t\t\tdataSource.setUsername(DATASOURCE_USER_NAME);\n\t\t\tdataSource.setPassword(DATASOURCE_USER_PASSWORD);\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class DelimitedJobConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemReader<Map<String, Object>> itemReader() {\n\n\t\t\tList<Map<String, Object>> items = new ArrayList<>(3);\n\n\t\t\titems.add(Collections.singletonMap(\"item_name\", \"foo\"));\n\t\t\titems.add(Collections.singletonMap(\"item_name\", \"bar\"));\n\t\t\titems.add(Collections.singletonMap(\"item_name\", \"baz\"));\n\n\t\t\treturn new ListItemReader<>(items);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class DelimitedDifferentKeyNameJobConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemReader<Map<String, Object>> itemReader() {\n\n\t\t\tList<Map<String, Object>> items = new ArrayList<>(3);\n\n\t\t\titems.add(Collections.singletonMap(\"item_foo\", \"foo\"));\n\t\t\titems.add(Collections.singletonMap(\"item_foo\", \"bar\"));\n\t\t\titems.add(Collections.singletonMap(\"item_foo\", \"baz\"));\n\n\t\t\treturn new ListItemReader<>(items);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class CustomSqlParameterSourceProviderConfiguration {\n\n\t\t@Bean\n\t\tpublic ItemSqlParameterSourceProvider<Map<String, Object>> itemSqlParameterSourceProvider() {\n\t\t\treturn item -> new MapSqlParameterSource(new HashMap<String, Object>() {\n\t\t\t\t{\n\t\t\t\t\tput(\"item_name\", item.get(\"item_foo\"));\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class ItemPreparedStatementSetterConfiguration {\n\n\t\t@Bean\n\t\tpublic ItemPreparedStatementSetter itemPreparedStatementSetter() {\n\t\t\treturn new ItemPreparedStatementSetter() {\n\t\t\t\t@Override\n\t\t\t\tpublic void setValues(Object item, PreparedStatement ps) throws SQLException {\n\t\t\t\t\tMap<String, Object> mapItem = (Map<String, Object>) item;\n\t\t\t\t\tStatementCreatorUtils.setParameterValue(ps, 1, SqlTypeValue.TYPE_UNKNOWN, mapItem.get(\"item_name\"));\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/jdbc/JdbcCursorItemReaderAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.jdbc;\n\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.h2.tools.Server;\nimport org.junit.jupiter.api.AfterAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.infrastructure.item.database.JdbcCursorItemReader;\nimport org.springframework.batch.infrastructure.item.support.ListItemWriter;\nimport org.springframework.batch.infrastructure.item.util.ExecutionContextUserSupport;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.AutoConfigureBefore;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.batch.autoconfigure.SingleStepJobAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.jdbc.BadSqlGrammarException;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.RowMapper;\nimport org.springframework.jdbc.datasource.DriverManagerDataSource;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.test.util.TestSocketUtils;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatThrownBy;\n\n/**\n * @author Michael Minella\n * @author Glenn Renfro\n */\npublic class JdbcCursorItemReaderAutoConfigurationTests {\n\n\tprivate final static String DATASOURCE_URL;\n\n\tprivate final static String DATASOURCE_USER_NAME = \"SA\";\n\n\tprivate final static String DATASOURCE_USER_PASSWORD = \"''\";\n\n\tprivate final static String DATASOURCE_DRIVER_CLASS_NAME = \"org.h2.Driver\";\n\n\tprivate static int randomPort;\n\n\tstatic {\n\t\trandomPort = TestSocketUtils.findAvailableTcpPort();\n\t\tDATASOURCE_URL = \"jdbc:h2:tcp://localhost:\" + randomPort + \"/mem:dataflow;DB_CLOSE_DELAY=-1;\"\n\t\t\t\t+ \"DB_CLOSE_ON_EXIT=FALSE\";\n\t}\n\n\t@AfterAll\n\tpublic static void clearDB() {\n\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\tdataSource.setDriverClassName(DATASOURCE_DRIVER_CLASS_NAME);\n\t\tdataSource.setUrl(DATASOURCE_URL);\n\t\tdataSource.setUsername(DATASOURCE_USER_NAME);\n\t\tdataSource.setPassword(DATASOURCE_USER_PASSWORD);\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\tjdbcTemplate.execute(\"TRUNCATE TABLE item\");\n\t\ttry {\n\t\t\tjdbcTemplate.execute(\"DROP TABLE BATCH_JOB_EXECUTION CASCADE\");\n\t\t\tjdbcTemplate.execute(\"DROP TABLE BATCH_JOB_INSTANCE CASCADE\");\n\t\t}\n\t\tcatch (BadSqlGrammarException e) {\n\t\t\tSystem.out.println(\"No tables to cleanup\");\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testIntegration() {\n\t\tApplicationContextRunner applicationContextRunner = applicationContextRunner().withPropertyValues(\n\t\t\t\t\"spring.batch.job.jobName=integrationJob\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.jdbccursoritemreader.name=fooReader\",\n\t\t\t\t\"spring.batch.job.jdbccursoritemreader.sql=select item_name from item\",\n\t\t\t\t\"spring.batch.jdbc.initialize-schema=always\",\n\t\t\t\t\"spring.batch.job.jdbcsinglestep.datasource.enable=false\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tList<Map<String, Object>> items = context.getBean(ListItemWriter.class).getWrittenItems();\n\n\t\t\tassertThat(items.size()).isEqualTo(3);\n\t\t\tassertThat(items.get(0).get(\"ITEM_NAME\")).isEqualTo(\"foo\");\n\t\t\tassertThat(items.get(1).get(\"ITEM_NAME\")).isEqualTo(\"bar\");\n\t\t\tassertThat(items.get(2).get(\"ITEM_NAME\")).isEqualTo(\"baz\");\n\t\t\tassertThatThrownBy(() -> context.getBean(\"readerSpringDataSource\"))\n\t\t\t\t.isInstanceOf(NoSuchBeanDefinitionException.class)\n\t\t\t\t.hasMessageContaining(\"No bean named 'readerSpringDataSource' available\");\n\t\t});\n\t}\n\n\tprivate ApplicationContextRunner applicationContextRunner() {\n\t\treturn new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskLauncherConfiguration.class, BaseConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, JdbcCursorItemReaderAutoConfiguration.class));\n\t}\n\n\t@Test\n\tpublic void testIntegrationReaderDataSourceEnabled() {\n\t\tApplicationContextRunner applicationContextRunner = applicationContextRunner().withPropertyValues(\n\t\t\t\t\"spring.batch.job.jobName=integrationReaderJob\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.jdbccursoritemreader.name=fooReader\",\n\t\t\t\t\"spring.batch.job.jdbccursoritemreader.sql=select item_name from item\",\n\t\t\t\t\"spring.batch.jdbc.initialize-schema=always\", \"spring.batch.job.jdbcsinglestep.datasource.enable=false\",\n\t\t\t\t\"spring.batch.job.jdbccursoritemreader.datasource.enable=true\",\n\t\t\t\t\"jdbccursoritemreader.datasource.url=\" + DATASOURCE_URL,\n\t\t\t\t\"jdbccursoritemreader.datasource.username=\" + DATASOURCE_USER_NAME,\n\t\t\t\t\"jdbccursoritemreader.datasource.password=\" + DATASOURCE_USER_PASSWORD,\n\t\t\t\t\"jdbccursoritemreader.datasource.driverClassName=\" + DATASOURCE_DRIVER_CLASS_NAME);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tList<Map<String, Object>> items = context.getBean(ListItemWriter.class).getWrittenItems();\n\n\t\t\tassertThat(items.size()).isEqualTo(3);\n\t\t\tassertThat(items.get(0).get(\"ITEM_NAME\")).isEqualTo(\"foo\");\n\t\t\tassertThat(items.get(1).get(\"ITEM_NAME\")).isEqualTo(\"bar\");\n\t\t\tassertThat(items.get(2).get(\"ITEM_NAME\")).isEqualTo(\"baz\");\n\t\t\tassertThat(context.getBean(\"jdbcCursorItemReaderSpringDataSource\")).isNotNull();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testCustomRowMapper() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskLauncherConfiguration.class, RowMapperConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, JdbcCursorItemReaderAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=rowMapperJob\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.jdbccursoritemreader.name=fooReader\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.sql=select * from item\",\n\t\t\t\t\t\"spring.batch.jdbc.initialize-schema=always\",\n\t\t\t\t\t\"spring.batch.job.jdbcsinglestep.datasource.enable=false\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tList<Map<String, Object>> items = context.getBean(ListItemWriter.class).getWrittenItems();\n\n\t\t\tassertThat(items.size()).isEqualTo(3);\n\t\t\tassertThat(items.get(0).get(\"item\")).isEqualTo(\"foo\");\n\t\t\tassertThat(items.get(1).get(\"item\")).isEqualTo(\"bar\");\n\t\t\tassertThat(items.get(2).get(\"item\")).isEqualTo(\"baz\");\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testRoseyScenario() {\n\t\tfinal ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskLauncherConfiguration.class, BaseConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, JdbcCursorItemReaderAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=roseyJob\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.jdbccursoritemreader.saveState=false\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.name=fooReader\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.maxItemCount=15\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.currentItemCount=2\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.fetchSize=4\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.maxRows=6\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.queryTimeout=8\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.ignoreWarnings=true\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.verifyCursorPosition=true\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.driverSupportsAbsolute=true\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.useSharedExtendedConnection=true\",\n\t\t\t\t\t\"spring.batch.job.jdbccursoritemreader.sql=select * from foo\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\n\t\t\tJdbcCursorItemReader<Map<String, Object>> itemReader = context.getBean(JdbcCursorItemReader.class);\n\n\t\t\tvalidateBean(itemReader);\n\t\t});\n\t}\n\n\tprivate void validateBean(JdbcCursorItemReader itemReader) {\n\t\tassertThat(itemReader.getSql()).isEqualTo(\"select * from foo\");\n\t\tassertThat(itemReader.getDataSource()).isNotNull();\n\t\tassertThat((Boolean) ReflectionTestUtils.getField(itemReader, \"saveState\")).isFalse();\n\t\tassertThat(ReflectionTestUtils.getField(\n\t\t\t\t(ExecutionContextUserSupport) ReflectionTestUtils.getField(itemReader, \"executionContextUserSupport\"),\n\t\t\t\t\"name\"))\n\t\t\t.isEqualTo(\"fooReader\");\n\t\tassertThat((Integer) ReflectionTestUtils.getField(itemReader, \"maxItemCount\")).isEqualTo(15);\n\t\tassertThat((Integer) ReflectionTestUtils.getField(itemReader, \"currentItemCount\")).isEqualTo(2);\n\t\tassertThat((Integer) ReflectionTestUtils.getField(itemReader, \"fetchSize\")).isEqualTo(4);\n\t\tassertThat((Integer) ReflectionTestUtils.getField(itemReader, \"maxRows\")).isEqualTo(6);\n\t\tassertThat((Integer) ReflectionTestUtils.getField(itemReader, \"queryTimeout\")).isEqualTo(8);\n\t\tassertThat((Boolean) ReflectionTestUtils.getField(itemReader, \"ignoreWarnings\")).isTrue();\n\t\tassertThat((Boolean) ReflectionTestUtils.getField(itemReader, \"verifyCursorPosition\")).isTrue();\n\t\tassertThat((Boolean) ReflectionTestUtils.getField(itemReader, \"driverSupportsAbsolute\")).isTrue();\n\t\tassertThat((Boolean) ReflectionTestUtils.getField(itemReader, \"useSharedExtendedConnection\")).isTrue();\n\t}\n\n\t@Test\n\tpublic void testNoName() {\n\t\tfinal ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskLauncherConfiguration.class, BaseConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, JdbcCursorItemReaderAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=noNameJob\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\");\n\n\t\tassertThatThrownBy(() -> {\n\t\t\trunTest(applicationContextRunner);\n\t\t}).isInstanceOf(IllegalStateException.class).hasMessageContaining(\"UnsatisfiedDependencyException\");\n\t}\n\n\t@Test\n\tpublic void testSqlName() {\n\t\tfinal ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskLauncherConfiguration.class, BaseConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, JdbcCursorItemReaderAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.jdbccursoritemreader.name=fooReader\");\n\n\t\tassertThatThrownBy(() -> {\n\t\t\trunTest(applicationContextRunner);\n\t\t}).isInstanceOf(IllegalStateException.class).hasMessageContaining(\"UnsatisfiedDependencyException\");\n\t}\n\n\tprivate void runTest(ApplicationContextRunner applicationContextRunner) {\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\t\t});\n\t}\n\n\t@AutoConfigureBefore({ JdbcCursorItemReaderAutoConfiguration.class,\n\t\t\tJDBCSingleStepDataSourceAutoConfiguration.class })\n\t@Configuration\n\tpublic static class TaskLauncherConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\tprivate static Server defaultServer;\n\n\t\t@Bean\n\t\tpublic Server initH2TCPServer() {\n\t\t\tServer server = null;\n\t\t\ttry {\n\t\t\t\tif (defaultServer == null) {\n\t\t\t\t\tserver = Server\n\t\t\t\t\t\t.createTcpServer(\"-ifNotExists\", \"-tcp\", \"-tcpAllowOthers\", \"-tcpPort\",\n\t\t\t\t\t\t\t\tString.valueOf(randomPort))\n\t\t\t\t\t\t.start();\n\t\t\t\t\tdefaultServer = server;\n\t\t\t\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\t\t\t\tdataSource.setDriverClassName(DATASOURCE_DRIVER_CLASS_NAME);\n\t\t\t\t\tdataSource.setUrl(DATASOURCE_URL);\n\t\t\t\t\tdataSource.setUsername(DATASOURCE_USER_NAME);\n\t\t\t\t\tdataSource.setPassword(DATASOURCE_USER_PASSWORD);\n\t\t\t\t\tClassPathResource setupResource = new ClassPathResource(\"schema-h2.sql\");\n\t\t\t\t\tResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator(setupResource);\n\t\t\t\t\tresourceDatabasePopulator.setContinueOnError(true);\n\t\t\t\t\tresourceDatabasePopulator.execute(dataSource);\n\n\t\t\t\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\t\t\t\tjdbcTemplate.execute(\"TRUNCATE TABLE item\");\n\t\t\t\t\tjdbcTemplate.execute(\"INSERT INTO item VALUES ('foo')\");\n\t\t\t\t\tjdbcTemplate.execute(\"INSERT INTO item VALUES ('bar')\");\n\t\t\t\t\tjdbcTemplate.execute(\"INSERT INTO item VALUES ('baz')\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (SQLException e) {\n\t\t\t\tthrow new IllegalStateException(e);\n\t\t\t}\n\t\t\treturn defaultServer;\n\t\t}\n\n\t\t@Bean\n\t\tpublic DataSource dataSource(Server server) {\n\t\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\t\tdataSource.setDriverClassName(DATASOURCE_DRIVER_CLASS_NAME);\n\t\t\tdataSource.setUrl(DATASOURCE_URL);\n\t\t\tdataSource.setUsername(DATASOURCE_USER_NAME);\n\t\t\tdataSource.setPassword(DATASOURCE_USER_PASSWORD);\n\t\t\treturn dataSource;\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class BaseConfiguration {\n\n\t\t@Bean\n\t\tpublic ListItemWriter<Map<String, Object>> itemWriter() {\n\t\t\treturn new ListItemWriter<>();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class RowMapperConfiguration {\n\n\t\t@Bean\n\t\tpublic RowMapper<Map<String, Object>> rowMapper() {\n\t\t\treturn (rs, rowNum) -> {\n\t\t\t\tMap<String, Object> item = new HashMap<>();\n\n\t\t\t\titem.put(\"item\", rs.getString(\"item_name\"));\n\n\t\t\t\treturn item;\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemWriter<Map<String, Object>> itemWriter() {\n\t\t\treturn new ListItemWriter<>();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/kafka/KafkaItemReaderAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.kafka;\n\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\nimport org.apache.kafka.clients.admin.NewTopic;\nimport org.apache.kafka.clients.producer.Producer;\nimport org.apache.kafka.clients.producer.ProducerRecord;\nimport org.apache.kafka.common.serialization.StringSerializer;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.infrastructure.item.support.ListItemWriter;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.batch.autoconfigure.SingleStepJobAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.core.DefaultKafkaProducerFactory;\nimport org.springframework.kafka.support.serializer.JsonDeserializer;\nimport org.springframework.kafka.support.serializer.JsonSerializer;\nimport org.springframework.kafka.test.EmbeddedKafkaBroker;\nimport org.springframework.kafka.test.context.EmbeddedKafka;\nimport org.springframework.kafka.test.utils.KafkaTestUtils;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@EmbeddedKafka(partitions = 1, topics = { \"test\" })\npublic class KafkaItemReaderAutoConfigurationTests {\n\n\tprivate static EmbeddedKafkaBroker embeddedKafkaBroker;\n\n\t@BeforeAll\n\tpublic static void setupTest(EmbeddedKafkaBroker embeddedKafka) {\n\t\tembeddedKafkaBroker = embeddedKafka;\n\t\tembeddedKafka.addTopics(new NewTopic(\"topic1\", 1, (short) 1), new NewTopic(\"topic2\", 2, (short) 1),\n\t\t\t\tnew NewTopic(\"topic3\", 1, (short) 1));\n\t}\n\n\t@Test\n\tpublic void testBaseKafkaItemReader() {\n\t\tfinal String topicName = \"topic1\";\n\t\tpopulateSingleTopic(topicName);\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(CustomMappingConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tKafkaItemReaderAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\",\n\t\t\t\t\t\"spring.kafka.consumer.bootstrap-servers=\" + embeddedKafkaBroker.getBrokersAsString(),\n\t\t\t\t\t\"spring.kafka.consumer.group-id=1\", \"spring.batch.job.kafkaitemreader.name=kafkaItemReader\",\n\t\t\t\t\t\"spring.batch.job.kafkaitemreader.poll-time-out-in-seconds=2\",\n\t\t\t\t\t\"spring.batch.job.kafkaitemreader.topic=\" + topicName,\n\t\t\t\t\t\"spring.kafka.consumer.value-deserializer=\" + JsonDeserializer.class.getName());\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tListItemWriter itemWriter = context.getBean(ListItemWriter.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tList<Map<String, Object>> writtenItems = itemWriter.getWrittenItems();\n\n\t\t\tassertThat(writtenItems.size()).isEqualTo(4);\n\t\t\tassertThat(writtenItems.get(0).get(\"first_name\")).isEqualTo(\"jane\");\n\t\t\tassertThat(writtenItems.get(1).get(\"first_name\")).isEqualTo(\"john\");\n\t\t\tassertThat(writtenItems.get(2).get(\"first_name\")).isEqualTo(\"susan\");\n\t\t\tassertThat(writtenItems.get(3).get(\"first_name\")).isEqualTo(\"jim\");\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testBaseKafkaItemReaderMultiplePartitions() {\n\t\tfinal String topicName = \"topic2\";\n\t\tpopulateSingleTopic(topicName);\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(CustomMappingConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tKafkaItemReaderAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\",\n\t\t\t\t\t\"spring.kafka.consumer.bootstrap-servers=\" + embeddedKafkaBroker.getBrokersAsString(),\n\t\t\t\t\t\"spring.kafka.consumer.group-id=1\", \"spring.batch.job.kafkaitemreader.name=kafkaItemReader\",\n\t\t\t\t\t\"spring.batch.job.kafkaitemreader.partitions=0,1\",\n\t\t\t\t\t\"spring.batch.job.kafkaitemreader.poll-time-out-in-seconds=2\",\n\t\t\t\t\t\"spring.batch.job.kafkaitemreader.topic=\" + topicName,\n\t\t\t\t\t\"spring.kafka.consumer.value-deserializer=\" + JsonDeserializer.class.getName());\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tListItemWriter itemWriter = context.getBean(ListItemWriter.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tbasicValidation(itemWriter);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testBaseKafkaItemReaderPollTimeoutDefault() {\n\t\tfinal String topicName = \"topic3\";\n\t\tpopulateSingleTopic(topicName);\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(CustomMappingConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tKafkaItemReaderAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\",\n\t\t\t\t\t\"spring.kafka.consumer.bootstrap-servers=\" + embeddedKafkaBroker.getBrokersAsString(),\n\t\t\t\t\t\"spring.kafka.consumer.group-id=1\", \"spring.batch.job.kafkaitemreader.name=kafkaItemReader\",\n\t\t\t\t\t\"spring.batch.job.kafkaitemreader.topic=\" + topicName,\n\t\t\t\t\t\"spring.kafka.consumer.value-deserializer=\" + JsonDeserializer.class.getName());\n\t\tDate startTime = new Date();\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\t\tJob job = context.getBean(Job.class);\n\n\t\t\tListItemWriter itemWriter = context.getBean(ListItemWriter.class);\n\n\t\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\t\t\tDate endTime = new Date();\n\t\t\tlong seconds = (endTime.getTime() - startTime.getTime()) / 1000;\n\t\t\tassertThat(seconds).isGreaterThanOrEqualTo(30);\n\t\t\tbasicValidation(itemWriter);\n\t\t});\n\t}\n\n\tprivate void basicValidation(ListItemWriter itemWriter) {\n\t\tList<Map<String, Object>> writtenItems = itemWriter.getWrittenItems();\n\t\tassertThat(writtenItems.size()).isEqualTo(4);\n\t\tList<Object> results = new ArrayList<>();\n\t\tfor (int i = 0; i < 4; i++) {\n\t\t\tresults.add(writtenItems.get(i).get(\"first_name\"));\n\t\t}\n\n\t\tassertThat(results).contains(\"jane\", \"john\", \"susan\", \"jim\");\n\t}\n\n\tprivate void populateSingleTopic(String topic) {\n\t\tMap<String, Object> configps = new HashMap<>(KafkaTestUtils.producerProps(embeddedKafkaBroker));\n\t\tProducer<String, Object> producer = new DefaultKafkaProducerFactory<>(configps, new StringSerializer(),\n\t\t\t\tnew JsonSerializer<>())\n\t\t\t.createProducer();\n\t\tMap<String, Object> testMap = new HashMap<>();\n\t\ttestMap.put(\"first_name\", \"jane\");\n\t\tproducer.send(new ProducerRecord<>(topic, \"my-aggregate-id\", testMap));\n\t\ttestMap = new HashMap<>();\n\t\ttestMap.put(\"first_name\", \"john\");\n\t\tproducer.send(new ProducerRecord<>(topic, \"my-aggregate-id\", testMap));\n\t\ttestMap = new HashMap<>();\n\t\ttestMap.put(\"first_name\", \"susan\");\n\t\tproducer.send(new ProducerRecord<>(topic, \"my-aggregate-id\", testMap));\n\t\ttestMap = new HashMap<>();\n\t\ttestMap.put(\"first_name\", \"jim\");\n\t\tproducer.send(new ProducerRecord<>(topic, \"my-aggregate-id\", testMap));\n\t\tproducer.flush();\n\t\tproducer.close();\n\t}\n\n\t@Configuration\n\tpublic static class CustomMappingConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemWriter<Map<String, Object>> itemWriter() {\n\t\t\treturn new ListItemWriter<>();\n\t\t}\n\n\t\t@Bean\n\t\tpublic SslBundles sslBundles() {\n\t\t\treturn new SslBundles() {\n\t\t\t\t@Override\n\t\t\t\tpublic SslBundle getBundle(String name) throws NoSuchSslBundleException {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void addBundleUpdateHandler(String name, Consumer<SslBundle> updateHandler)\n\t\t\t\t\t\tthrows NoSuchSslBundleException {\n\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void addBundleRegisterHandler(BiConsumer<String, SslBundle> registerHandler) {\n\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic List<String> getBundleNames() {\n\t\t\t\t\treturn List.of();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/kafka/KafkaItemWriterTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.kafka;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.BiConsumer;\n\nimport org.apache.kafka.clients.consumer.Consumer;\nimport org.apache.kafka.clients.consumer.ConsumerRecords;\nimport org.apache.kafka.common.serialization.StringDeserializer;\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.infrastructure.item.support.ListItemReader;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.ssl.NoSuchSslBundleException;\nimport org.springframework.boot.ssl.SslBundle;\nimport org.springframework.boot.ssl.SslBundles;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.batch.autoconfigure.SingleStepJobAutoConfiguration;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.kafka.core.DefaultKafkaConsumerFactory;\nimport org.springframework.kafka.support.serializer.JsonDeserializer;\nimport org.springframework.kafka.test.EmbeddedKafkaBroker;\nimport org.springframework.kafka.test.context.EmbeddedKafka;\nimport org.springframework.kafka.test.utils.KafkaTestUtils;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static java.util.Collections.singleton;\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@EmbeddedKafka(partitions = 1, topics = { \"topic1\" })\npublic class KafkaItemWriterTests {\n\n\tprivate static EmbeddedKafkaBroker embeddedKafkaBroker;\n\n\t@BeforeAll\n\tpublic static void setupTest(EmbeddedKafkaBroker embeddedKafka) {\n\t\tembeddedKafkaBroker = embeddedKafka;\n\t\tembeddedKafka.addTopics(\"topic2\");\n\t}\n\n\t@Test\n\tpublic void testBaseKafkaItemWriter() {\n\t\tfinal String topicName = \"topic1\";\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(CustomMappingConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tKafkaItemWriterAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=job\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\",\n\t\t\t\t\t\"spring.kafka.producer.bootstrap-servers=\" + embeddedKafkaBroker.getBrokersAsString(),\n\t\t\t\t\t\"spring.kafka.producer.keySerializer=org.springframework.kafka.support.serializer.JsonSerializer\",\n\t\t\t\t\t\"spring.batch.job.kafkaitemwriter.topic=\" + topicName);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\twaitForTopicPopulation(context);\n\t\t\tvalidateResults(topicName);\n\t\t});\n\t}\n\n\tprivate void validateResults(String topicName) {\n\t\tMap<String, Object> configs = new HashMap<>(KafkaTestUtils.consumerProps(\"1\", \"false\", embeddedKafkaBroker));\n\t\tConsumer<String, Object> consumer = new DefaultKafkaConsumerFactory<>(configs, new StringDeserializer(),\n\t\t\t\tnew JsonDeserializer<>())\n\t\t\t.createConsumer();\n\t\tconsumer.subscribe(singleton(topicName));\n\n\t\tConsumerRecords<String, Object> consumerRecords = KafkaTestUtils.getRecords(consumer);\n\t\tassertThat(consumerRecords.count()).isEqualTo(5);\n\t\tList<Map<String, Object>> result = new ArrayList<>();\n\t\tconsumerRecords.forEach(cs -> {\n\t\t\tresult.add((Map<String, Object>) cs.value());\n\t\t});\n\t\tList<String> firstNames = new ArrayList<>();\n\t\tresult.forEach(s -> firstNames.add((String) s.get(\"first_name\")));\n\t\tassertThat(firstNames.size()).isEqualTo(5);\n\t\tassertThat(firstNames).contains(\"Jane\");\n\t\tassertThat(firstNames).contains(\"John\");\n\t\tassertThat(firstNames).contains(\"Liz\");\n\t\tassertThat(firstNames).contains(\"Cameron\");\n\t\tassertThat(firstNames).contains(\"Judy\");\n\t}\n\n\tprivate void waitForTopicPopulation(ApplicationContext context) throws Exception {\n\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\t\tJob job = context.getBean(Job.class);\n\t\tJobExecution jobExecution = jobOperator.start(job, new JobParameters());\n\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\tThread.sleep(1000);\n\t\t}\n\t}\n\n\t@Configuration\n\tpublic static class CustomMappingConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemReader<Map<String, Object>> itemReader() {\n\t\t\tList<Map<String, Object>> list = new ArrayList<>(5);\n\t\t\taddNameToReaderList(list, \"Jane\");\n\t\t\taddNameToReaderList(list, \"John\");\n\t\t\taddNameToReaderList(list, \"Liz\");\n\t\t\taddNameToReaderList(list, \"Cameron\");\n\t\t\taddNameToReaderList(list, \"Judy\");\n\t\t\treturn new ListItemReader<>(list);\n\t\t}\n\n\t\tprivate void addNameToReaderList(List<Map<String, Object>> itemReaderList, String value) {\n\t\t\tMap<String, Object> prepMap = new HashMap<>();\n\t\t\tprepMap.put(\"first_name\", value);\n\t\t\titemReaderList.add(prepMap);\n\t\t}\n\n\t\t@Bean\n\t\tpublic SslBundles sslBundles() {\n\t\t\treturn new SslBundles() {\n\t\t\t\t@Override\n\t\t\t\tpublic SslBundle getBundle(String name) throws NoSuchSslBundleException {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void addBundleUpdateHandler(String name, java.util.function.Consumer<SslBundle> updateHandler)\n\t\t\t\t\t\tthrows NoSuchSslBundleException {\n\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void addBundleRegisterHandler(BiConsumer<String, SslBundle> registerHandler) {\n\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic List<String> getBundleNames() {\n\t\t\t\t\treturn List.of();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/rabbit/AmqpItemReaderAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.rabbit;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Tag;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\n\nimport org.springframework.amqp.core.AmqpAdmin;\nimport org.springframework.amqp.core.AmqpTemplate;\nimport org.springframework.amqp.core.Queue;\nimport org.springframework.amqp.rabbit.connection.CachingConnectionFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.amqp.rabbit.core.RabbitAdmin;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.amqp.support.converter.JacksonJsonMessageConverter;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.infrastructure.item.support.ListItemWriter;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.batch.autoconfigure.SingleStepJobAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@Tag(\"DockerRequired\")\npublic class AmqpItemReaderAutoConfigurationTests {\n\n\tprivate static int amqpPort;\n\n\tprivate static String host;\n\n\tprivate RabbitTemplate template;\n\n\tprivate ConnectionFactory connectionFactory;\n\n\tstatic {\n\t\tGenericContainer rabbitmq = new RabbitMQContainer(\"rabbitmq:3.8.9\").withExposedPorts(5672);\n\t\trabbitmq.start();\n\t\tfinal Integer mappedPort = rabbitmq.getMappedPort(5672);\n\t\thost = rabbitmq.getHost();\n\t\tamqpPort = mappedPort;\n\t}\n\n\t@BeforeEach\n\tvoid setupTest() {\n\t\tthis.connectionFactory = new CachingConnectionFactory(host, amqpPort);\n\t\tthis.template = new RabbitTemplate(this.connectionFactory);\n\t\tthis.template.setMessageConverter(new JacksonJsonMessageConverter());\n\t\tAmqpAdmin admin = new RabbitAdmin(this.connectionFactory);\n\t\tadmin.declareQueue(new Queue(\"foo\"));\n\n\t\tMap<String, Object> testMap = new HashMap<>();\n\t\ttestMap.put(\"ITEM_NAME\", \"foo\");\n\t\tthis.template.convertAndSend(\"foo\", testMap);\n\t\ttestMap = new HashMap<>();\n\t\ttestMap.put(\"ITEM_NAME\", \"bar\");\n\t\tthis.template.convertAndSend(\"foo\", testMap);\n\t\ttestMap = new HashMap<>();\n\t\ttestMap.put(\"ITEM_NAME\", \"baz\");\n\t\tthis.template.convertAndSend(\"foo\", testMap);\n\t}\n\n\t@AfterEach\n\tvoid teardownTest() {\n\t\tAmqpAdmin admin = new RabbitAdmin(this.connectionFactory);\n\t\tadmin.deleteQueue(\"foo\");\n\t\tthis.template.destroy();\n\t}\n\n\t@Test\n\tvoid basicTest() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, AmqpItemReaderAutoConfiguration.class,\n\t\t\t\t\t\t\tRabbitAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=integrationJob\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.amqpitemreader.enabled=true\",\n\t\t\t\t\t\"spring.rabbitmq.template.default-receive-queue=foo\", \"spring.rabbitmq.host=\" + host,\n\t\t\t\t\t\"spring.rabbitmq.port=\" + amqpPort);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobExecution jobExecution = runJob(context);\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tvalidateBasicTest(context.getBean(ListItemWriter.class).getWrittenItems());\n\t\t});\n\t}\n\n\t@Test\n\tvoid basicTestWithItemType() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(ItemTypeConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, AmqpItemReaderAutoConfiguration.class,\n\t\t\t\t\t\t\tRabbitAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=integrationJob\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.amqpitemreader.enabled=true\",\n\t\t\t\t\t\"spring.rabbitmq.template.default-receive-queue=foo\", \"spring.rabbitmq.host=\" + host,\n\t\t\t\t\t\"spring.rabbitmq.port=\" + amqpPort);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobExecution jobExecution = runJob(context);\n\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\t\t\tvalidateBasicTest(context.getBean(ListItemWriter.class).getWrittenItems());\n\t\t});\n\t}\n\n\t@Test\n\tvoid useAmqpTemplateTest() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(MockTemplateConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tAmqpItemReaderAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.batch.job.jobName=integrationJob\", \"spring.batch.job.stepName=step1\",\n\t\t\t\t\t\"spring.batch.job.chunkSize=5\", \"spring.batch.job.amqpitemreader.enabled=true\",\n\t\t\t\t\t\"spring.rabbitmq.host=\" + host, \"spring.rabbitmq.port=\" + amqpPort);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\trunJob(context);\n\t\t\tAmqpTemplate amqpTemplate = context.getBean(AmqpTemplate.class);\n\t\t\tMockito.verify(amqpTemplate, Mockito.times(1)).receiveAndConvert();\n\t\t});\n\t}\n\n\tprivate JobExecution runJob(AssertableApplicationContext context) throws Exception {\n\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\t\tJob job = context.getBean(Job.class);\n\t\treturn jobOperator.start(job, new JobParameters());\n\t}\n\n\tprivate void validateBasicTest(List<Map<String, Object>> items) {\n\t\tassertThat(items.size()).isEqualTo(3);\n\t\tassertThat(items.get(0).get(\"ITEM_NAME\")).isEqualTo(\"foo\");\n\t\tassertThat(items.get(1).get(\"ITEM_NAME\")).isEqualTo(\"bar\");\n\t\tassertThat(items.get(2).get(\"ITEM_NAME\")).isEqualTo(\"baz\");\n\t}\n\n\tpublic static class MockTemplateConfiguration extends BaseConfiguration {\n\n\t\t@Bean\n\t\tAmqpTemplate amqpTemplateBean() {\n\t\t\treturn Mockito.mock(AmqpTemplate.class);\n\t\t};\n\n\t}\n\n\tpublic static class ItemTypeConfiguration extends BaseConfiguration {\n\n\t\t@Bean\n\t\tClass<?> itemTypeClass() {\n\t\t\treturn Map.class;\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class BaseConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic ListItemWriter<Map<String, Object>> itemWriter() {\n\t\t\treturn new ListItemWriter<>();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/rabbit/AmqpItemWriterAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.autoconfigure.rabbit;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Tag;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mockito;\nimport org.testcontainers.containers.GenericContainer;\nimport org.testcontainers.rabbitmq.RabbitMQContainer;\n\nimport org.springframework.amqp.core.AmqpAdmin;\nimport org.springframework.amqp.core.AmqpTemplate;\nimport org.springframework.amqp.core.Binding;\nimport org.springframework.amqp.core.Queue;\nimport org.springframework.amqp.core.TopicExchange;\nimport org.springframework.amqp.rabbit.connection.CachingConnectionFactory;\nimport org.springframework.amqp.rabbit.connection.ConnectionFactory;\nimport org.springframework.amqp.rabbit.core.RabbitAdmin;\nimport org.springframework.amqp.rabbit.core.RabbitTemplate;\nimport org.springframework.amqp.support.converter.JacksonJsonMessageConverter;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.infrastructure.item.ItemReader;\nimport org.springframework.batch.infrastructure.item.support.ListItemReader;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.amqp.autoconfigure.RabbitAutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.batch.autoconfigure.SingleStepJobAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.core.RowMapper;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@Tag(\"DockerRequired\")\npublic class AmqpItemWriterAutoConfigurationTests {\n\n\tprivate final static String QUEUE_NAME = \"foo\";\n\n\tprivate final static String EXCHANGE_NAME = \"fooexchange\";\n\n\tprivate static int amqpPort;\n\n\tprivate static String host;\n\n\tprivate static List<Map<String, Object>> sampleData;\n\n\tprivate RabbitTemplate template;\n\n\tprivate ConnectionFactory connectionFactory;\n\n\tprivate String[] configurations;\n\n\tstatic {\n\t\tGenericContainer rabbitmq = new RabbitMQContainer(\"rabbitmq:3.8.9\").withExposedPorts(5672);\n\t\trabbitmq.start();\n\t\tfinal Integer mappedPort = rabbitmq.getMappedPort(5672);\n\t\thost = rabbitmq.getHost();\n\t\tamqpPort = mappedPort;\n\t\tsampleData = new ArrayList<>(5);\n\t\taddNameToReaderList(sampleData, \"Jane\");\n\t\taddNameToReaderList(sampleData, \"John\");\n\t\taddNameToReaderList(sampleData, \"Liz\");\n\t\taddNameToReaderList(sampleData, \"Cameron\");\n\t\taddNameToReaderList(sampleData, \"Judy\");\n\t}\n\n\tprivate static void addNameToReaderList(List<Map<String, Object>> itemReaderList, String value) {\n\t\tMap<String, Object> prepMap = new HashMap<>();\n\t\tprepMap.put(\"first_name\", value);\n\t\titemReaderList.add(prepMap);\n\t}\n\n\t@BeforeEach\n\tvoid setupTest() {\n\t\tthis.connectionFactory = new CachingConnectionFactory(host, amqpPort);\n\t\tthis.template = new RabbitTemplate(this.connectionFactory);\n\t\tthis.template.setMessageConverter(new JacksonJsonMessageConverter());\n\t\tAmqpAdmin admin = new RabbitAdmin(this.connectionFactory);\n\t\tadmin.declareQueue(new Queue(QUEUE_NAME));\n\t\tadmin.declareExchange(new TopicExchange(EXCHANGE_NAME));\n\t\tadmin.declareBinding(new Binding(QUEUE_NAME, Binding.DestinationType.QUEUE, EXCHANGE_NAME, \"#\", null));\n\t\tthis.configurations = new String[] { \"spring.batch.job.jobName=integrationJob\",\n\t\t\t\t\"spring.batch.job.stepName=step1\", \"spring.batch.job.chunkSize=5\",\n\t\t\t\t\"spring.rabbitmq.template.exchange=\" + EXCHANGE_NAME, \"spring.rabbitmq.host=\" + host,\n\t\t\t\t\"spring.batch.job.amqpitemwriter.enabled=true\", \"spring.rabbitmq.port=\" + amqpPort };\n\t}\n\n\t@AfterEach\n\tvoid teardownTest() {\n\t\tAmqpAdmin admin = new RabbitAdmin(this.connectionFactory);\n\t\tadmin.deleteQueue(QUEUE_NAME);\n\t\tthis.template.destroy();\n\t}\n\n\t@Test\n\tvoid basicTest() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(BaseConfiguration.class)\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleStepJobAutoConfiguration.class, AmqpItemWriterAutoConfiguration.class,\n\t\t\t\t\t\t\tRabbitAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(this.configurations);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tJobExecution jobExecution = runJob(context);\n\t\t\tJobRepository jobRepository = context.getBean(JobRepository.class);\n\n\t\t\twhile (jobRepository.getJobExecution(jobExecution.getId()).isRunning()) {\n\t\t\t\tThread.sleep(1000);\n\t\t\t}\n\n\t\t\tfor (Map<String, Object> sampleEntry : sampleData) {\n\t\t\t\tMap<String, Object> map = (Map<String, Object>) template.receiveAndConvert(QUEUE_NAME);\n\t\t\t\tassertThat(map.get(\"first_name\")).isEqualTo(sampleEntry.get(\"first_name\"));\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tvoid useAmqpTemplateTest() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(MockConfiguration.class)\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tBatchAutoConfiguration.class, SingleStepJobAutoConfiguration.class,\n\t\t\t\t\tAmqpItemWriterAutoConfiguration.class, DataSourceAutoConfiguration.class))\n\t\t\t.withPropertyValues(this.configurations);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\trunJob(context);\n\t\t\tAmqpTemplate amqpTemplate = context.getBean(AmqpTemplate.class);\n\t\t\tMockito.verify(amqpTemplate, Mockito.times(5)).convertAndSend(Mockito.any());\n\t\t});\n\t}\n\n\tprivate JobExecution runJob(AssertableApplicationContext context) throws Exception {\n\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\n\t\tJob job = context.getBean(Job.class);\n\n\t\treturn jobOperator.start(job, new JobParameters());\n\t}\n\n\t@Configuration\n\tpublic static class BaseConfiguration extends ItemWriterConfiguration {\n\n\t}\n\n\t@Configuration\n\tpublic static class MockConfiguration extends ItemWriterConfiguration {\n\n\t\t@Bean\n\t\tAmqpTemplate amqpTemplateBean() {\n\t\t\treturn Mockito.mock(AmqpTemplate.class);\n\t\t}\n\n\t}\n\n\tpublic static class ItemWriterConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager platformTransactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic RowMapper<Map<String, Object>> rowMapper() {\n\t\t\treturn (rs, rowNum) -> {\n\t\t\t\tMap<String, Object> item = new HashMap<>();\n\n\t\t\t\titem.put(\"item\", rs.getString(\"item_name\"));\n\n\t\t\t\treturn item;\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tpublic ItemReader<Map<String, Object>> itemWriter() {\n\n\t\t\treturn new ListItemReader<>(sampleData);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/resources/logback-test.xml",
    "content": "<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t<logger name=\"org.apache.http\" level=\"WARN\"/>\n\t<logger name=\"com.github.dockerjava\" level=\"WARN\"/>\n\t<logger name=\"org.zeroturnaround.exec\" level=\"WARN\"/>\n</configuration>\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/resources/schema-h2.sql",
    "content": "CREATE TABLE IF NOT EXISTS item\n(\n   item_name varchar(55)\n);\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/resources/test.txt",
    "content": "1 2 3 4 5 six\n# This should be ignored\n7 8 9 1011twelve\n$ So should this\n1314151617eighteen\n1920212223twenty four\n1526272829thirty\n3132333435thirty six\n"
  },
  {
    "path": "spring-cloud-starter-single-step-batch-job/src/test/resources/testUTF8.csv",
    "content": "1@2@3@4@5@six\n# This should be ignored\n7@8@9@10@11@twelve\n$ So should this\n13@14@15@16@17@eighteen\n19@20@21@22@23@%twenty four%\n15@26@27@28@29@thirty\n31@32@33@34@35@thirty six\n37@38@39@40@41@forty two\n43@44@45@46@47@forty eight\n49@50@51@52@53@fifty four\n55@56@57@58@59@sixty\n"
  },
  {
    "path": "spring-cloud-starter-task/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<artifactId>spring-cloud-task-parent</artifactId>\n\t\t<version>5.0.2-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>spring-cloud-starter-task</artifactId>\n\t<packaging>jar</packaging>\n\t<name>Spring Cloud Task Starter</name>\n\t<description>Spring Boot starter for Spring Cloud Task</description>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-task-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-task-batch</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-task-stream</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "spring-cloud-task-batch/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<artifactId>spring-cloud-task-parent</artifactId>\n\t\t<version>5.0.2-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>spring-cloud-task-batch</artifactId>\n\t<packaging>jar</packaging>\n\t<name>Spring Cloud Task Batch</name>\n\t<description>Module for use when combining Spring Cloud Task with Spring Batch\n\t</description>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-task-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-batch</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.batch</groupId>\n\t\t\t<artifactId>spring-batch-integration</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t\t<version>${spring-boot.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.assertj</groupId>\n\t\t\t<artifactId>assertj-core</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter-api</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-autoconfigure-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-batch</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mockito</groupId>\n\t\t\t<artifactId>mockito-junit-jupiter</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n </dependencies>\n</project>\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/JobLaunchCondition.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.configuration;\n\nimport org.springframework.boot.autoconfigure.condition.AllNestedConditions;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\n\n/**\n * Evaluates if the correct conditions have been met to create a TaskJobLauncher.\n *\n * @author Glenn Renfro\n * @since 2.2.0\n */\npublic class JobLaunchCondition extends AllNestedConditions {\n\n\tpublic JobLaunchCondition() {\n\t\tsuper(ConfigurationPhase.PARSE_CONFIGURATION);\n\t}\n\n\t@ConditionalOnProperty(name = \"spring.cloud.task.batch.fail-on-job-failure\", havingValue = \"true\")\n\tstatic class FailOnJobFailureCondition {\n\n\t}\n\n\t@ConditionalOnProperty(prefix = \"spring.batch.job\", name = \"enabled\", havingValue = \"true\", matchIfMissing = true)\n\tstatic class SpringBatchJobCondition {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchAutoConfiguration.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.configuration;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.cloud.task.batch.listener.TaskBatchExecutionListener;\nimport org.springframework.cloud.task.configuration.TaskConfigurer;\nimport org.springframework.cloud.task.configuration.TaskProperties;\nimport org.springframework.cloud.task.listener.TaskLifecycleListener;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Provides auto configuration for the {@link TaskBatchExecutionListener}.\n *\n * The spring.cloud.task.batch.listener.enable is deprecated,\n * spring.cloud.task.batch.listener.enabled should be used.\n *\n * @author Michael Minella\n */\n@AutoConfiguration\n@ConditionalOnBean({ Job.class, TaskLifecycleListener.class })\n@ConditionalOnProperty(name = { \"spring.cloud.task.batch.listener.enable\", \"spring.cloud.task.batch.listener.enabled\" },\n\t\thavingValue = \"true\", matchIfMissing = true)\npublic class TaskBatchAutoConfiguration {\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tpublic static TaskBatchExecutionListenerBeanPostProcessor batchTaskExecutionListenerBeanPostProcessor() {\n\t\treturn new TaskBatchExecutionListenerBeanPostProcessor();\n\t}\n\n\t/**\n\t * Auto configuration for {@link TaskBatchExecutionListener}.\n\t */\n\t@AutoConfiguration\n\t@ConditionalOnMissingBean(name = \"taskBatchExecutionListener\")\n\t@EnableConfigurationProperties(TaskProperties.class)\n\tpublic static class TaskBatchExecutionListenerAutoconfiguration {\n\n\t\t@Autowired\n\t\tprivate ApplicationContext context;\n\n\t\t@Autowired\n\t\tprivate TaskProperties taskProperties;\n\n\t\t@Bean\n\t\tpublic TaskBatchExecutionListenerFactoryBean taskBatchExecutionListener(TaskExplorer taskExplorer) {\n\t\t\tTaskConfigurer taskConfigurer = null;\n\t\t\tif (!this.context.getBeansOfType(TaskConfigurer.class).isEmpty()) {\n\t\t\t\ttaskConfigurer = this.context.getBean(TaskConfigurer.class);\n\t\t\t}\n\t\t\tif (taskConfigurer != null && taskConfigurer.getTaskDataSource() != null) {\n\t\t\t\treturn new TaskBatchExecutionListenerFactoryBean(taskConfigurer.getTaskDataSource(), taskExplorer,\n\t\t\t\t\t\tthis.taskProperties.getTablePrefix());\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn new TaskBatchExecutionListenerFactoryBean(null, taskExplorer,\n\t\t\t\t\t\tthis.taskProperties.getTablePrefix());\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchExecutionListenerBeanPostProcessor.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.configuration;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.batch.core.job.AbstractJob;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.cloud.task.batch.listener.TaskBatchExecutionListener;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.util.Assert;\n\n/**\n * Injects a configured {@link TaskBatchExecutionListener} into any batch jobs (beans\n * assignable to {@link AbstractJob}) that are executed within the scope of a task. The\n * context this is used within is expected to have only one bean of type\n * {@link TaskBatchExecutionListener}.\n *\n * @author Michael Minella\n */\npublic class TaskBatchExecutionListenerBeanPostProcessor implements BeanPostProcessor {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\tprivate List<String> jobNames = new ArrayList<>();\n\n\t@Override\n\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\t\treturn bean;\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (this.jobNames.size() > 0 && !this.jobNames.contains(beanName)) {\n\t\t\treturn bean;\n\t\t}\n\t\tint length = this.applicationContext.getBeanNamesForType(TaskBatchExecutionListener.class).length;\n\n\t\tif (bean instanceof AbstractJob) {\n\t\t\tif (length != 1) {\n\t\t\t\tthrow new IllegalStateException(\"The application context is required to \"\n\t\t\t\t\t\t+ \"have exactly 1 instance of the TaskBatchExecutionListener but has \" + length);\n\t\t\t}\n\t\t\t((AbstractJob) bean)\n\t\t\t\t.registerJobExecutionListener(this.applicationContext.getBean(TaskBatchExecutionListener.class));\n\t\t}\n\t\treturn bean;\n\t}\n\n\tpublic void setJobNames(List<String> jobNames) {\n\t\tAssert.notNull(jobNames, \"A list is required\");\n\n\t\tthis.jobNames = jobNames;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchExecutionListenerFactoryBean.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.configuration;\n\nimport java.lang.reflect.Field;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.aop.framework.Advised;\nimport org.springframework.aop.support.AopUtils;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.cloud.task.batch.listener.TaskBatchExecutionListener;\nimport org.springframework.cloud.task.batch.listener.support.JdbcTaskBatchDao;\nimport org.springframework.cloud.task.batch.listener.support.MapTaskBatchDao;\nimport org.springframework.cloud.task.configuration.TaskProperties;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;\nimport org.springframework.cloud.task.repository.support.SimpleTaskExplorer;\nimport org.springframework.util.Assert;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * {@link FactoryBean} for a {@link TaskBatchExecutionListener}. Provides a jdbc based\n * listener if there is a {@link DataSource} available. Otherwise, builds a listener that\n * uses the map based implementation.\n *\n * @author Michael Minella\n */\npublic class TaskBatchExecutionListenerFactoryBean implements FactoryBean<TaskBatchExecutionListener> {\n\n\tprivate TaskBatchExecutionListener listener;\n\n\tprivate DataSource dataSource;\n\n\tprivate TaskExplorer taskExplorer;\n\n\tprivate String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX;\n\n\t/**\n\t * Initializes the TaskBatchExecutionListenerFactoryBean and defaults the tablePrefix\n\t * to {@link TaskProperties#DEFAULT_TABLE_PREFIX}.\n\t * @param dataSource the dataSource to use for the TaskBatchExecutionListener.\n\t * @param taskExplorer the taskExplorer to use for the TaskBatchExecutionListener.\n\t */\n\tpublic TaskBatchExecutionListenerFactoryBean(DataSource dataSource, TaskExplorer taskExplorer) {\n\t\tthis.dataSource = dataSource;\n\t\tthis.taskExplorer = taskExplorer;\n\t}\n\n\t/**\n\t * Initializes the TaskBatchExecutionListenerFactoryBean.\n\t * @param dataSource the dataSource to use for the TaskBatchExecutionListener.\n\t * @param taskExplorer the taskExplorer to use for the TaskBatchExecutionListener.\n\t * @param tablePrefix the prefix for the task tables accessed by the\n\t * TaskBatchExecutionListener.\n\t */\n\tpublic TaskBatchExecutionListenerFactoryBean(DataSource dataSource, TaskExplorer taskExplorer, String tablePrefix) {\n\t\tthis(dataSource, taskExplorer);\n\t\tAssert.hasText(tablePrefix, \"tablePrefix must not be null nor empty.\");\n\t\tthis.tablePrefix = tablePrefix;\n\t}\n\n\t@Override\n\tpublic TaskBatchExecutionListener getObject() throws Exception {\n\t\tif (this.listener != null) {\n\t\t\treturn this.listener;\n\t\t}\n\t\tif (this.dataSource == null) {\n\t\t\tthis.listener = new TaskBatchExecutionListener(getMapTaskBatchDao());\n\t\t}\n\t\telse {\n\t\t\tthis.listener = new TaskBatchExecutionListener(new JdbcTaskBatchDao(this.dataSource, this.tablePrefix));\n\t\t}\n\n\t\treturn this.listener;\n\t}\n\n\t@Override\n\tpublic Class<?> getObjectType() {\n\t\treturn TaskBatchExecutionListener.class;\n\t}\n\n\t@Override\n\tpublic boolean isSingleton() {\n\t\treturn true;\n\t}\n\n\tprivate MapTaskBatchDao getMapTaskBatchDao() throws Exception {\n\t\tField taskExecutionDaoField = ReflectionUtils.findField(SimpleTaskExplorer.class, \"taskExecutionDao\");\n\t\ttaskExecutionDaoField.setAccessible(true);\n\n\t\tMapTaskExecutionDao taskExecutionDao;\n\n\t\tif (AopUtils.isJdkDynamicProxy(this.taskExplorer)) {\n\t\t\tSimpleTaskExplorer dereferencedTaskRepository = (SimpleTaskExplorer) ((Advised) this.taskExplorer)\n\t\t\t\t.getTargetSource()\n\t\t\t\t.getTarget();\n\n\t\t\ttaskExecutionDao = (MapTaskExecutionDao) ReflectionUtils.getField(taskExecutionDaoField,\n\t\t\t\t\tdereferencedTaskRepository);\n\t\t}\n\t\telse {\n\t\t\ttaskExecutionDao = (MapTaskExecutionDao) ReflectionUtils.getField(taskExecutionDaoField, this.taskExplorer);\n\t\t}\n\n\t\treturn new MapTaskBatchDao(taskExecutionDao.getBatchJobAssociations());\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchProperties.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.configuration;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Establish properties to be used for how Tasks work with Spring Batch.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @since 2.0.0\n */\n@ConfigurationProperties(prefix = \"spring.cloud.task.batch\")\npublic class TaskBatchProperties {\n\n\tprivate static final long DEFAULT_POLL_INTERVAL = 5000L;\n\n\t/**\n\t * Comma-separated list of job names to execute on startup (for instance,\n\t * `job1,job2`). By default, all Jobs found in the context are executed.\n\t * @deprecated use spring.batch.job.name instead of spring.cloud.task.batch.jobNames.\n\t */\n\tprivate String jobNames = \"\";\n\n\t/**\n\t * The order for the {@code ApplicationRunner} used to run batch jobs when\n\t * {@code spring.cloud.task.batch.fail-on-job-failure=true}. Defaults to 0 (same as\n\t * the\n\t * {@link org.springframework.boot.batch.autoconfigure.JobLauncherApplicationRunner}).\n\t */\n\tprivate int applicationRunnerOrder = 0;\n\n\t/**\n\t * Fixed delay in milliseconds that Spring Cloud Task will wait when checking if\n\t * {@link org.springframework.batch.core.JobExecution}s have completed, when\n\t * spring.cloud.task.batch.failOnJobFailure is set to true. Defaults to 5000.\n\t */\n\tprivate long failOnJobFailurePollInterval = DEFAULT_POLL_INTERVAL;\n\n\tpublic String getJobNames() {\n\t\treturn this.jobNames;\n\t}\n\n\tpublic void setJobNames(String jobNames) {\n\t\tthis.jobNames = jobNames;\n\t}\n\n\t@Deprecated\n\tpublic int getCommandLineRunnerOrder() {\n\t\treturn this.applicationRunnerOrder;\n\t}\n\n\t@Deprecated\n\tpublic void setCommandLineRunnerOrder(int commandLineRunnerOrder) {\n\t\tthis.applicationRunnerOrder = commandLineRunnerOrder;\n\t}\n\n\tpublic int getApplicationRunnerOrder() {\n\t\treturn this.applicationRunnerOrder;\n\t}\n\n\tpublic void setApplicationRunnerOrder(int applicationRunnerOrder) {\n\t\tthis.applicationRunnerOrder = applicationRunnerOrder;\n\t}\n\n\tpublic long getFailOnJobFailurePollInterval() {\n\t\treturn this.failOnJobFailurePollInterval;\n\t}\n\n\tpublic void setFailOnJobFailurePollInterval(long failOnJobFailurePollInterval) {\n\t\tthis.failOnJobFailurePollInterval = failOnJobFailurePollInterval;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherApplicationRunnerFactoryBean.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.configuration;\n\nimport java.util.List;\n\nimport org.springframework.batch.core.configuration.JobRegistry;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.boot.batch.autoconfigure.BatchProperties;\nimport org.springframework.cloud.task.batch.handler.TaskJobLauncherApplicationRunner;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.ApplicationEventPublisherAware;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Factory bean for creating an instance of {@link TaskJobLauncherApplicationRunner}.\n *\n * @author Glenn Renfro\n * @since 2.3.0\n */\npublic class TaskJobLauncherApplicationRunnerFactoryBean\n\t\timplements FactoryBean<TaskJobLauncherApplicationRunner>, ApplicationEventPublisherAware {\n\n\tprivate final JobOperator jobOperator;\n\n\tprivate final List<Job> jobs;\n\n\tprivate String jobName;\n\n\tprivate final JobRegistry jobRegistry;\n\n\tprivate Integer order;\n\n\tprivate final TaskBatchProperties taskBatchProperties;\n\n\tprivate final JobRepository jobRepository;\n\n\tprivate ApplicationEventPublisher applicationEventPublisher;\n\n\tpublic TaskJobLauncherApplicationRunnerFactoryBean(JobOperator jobOperator, List<Job> jobs,\n\t\t\tTaskBatchProperties taskBatchProperties, JobRegistry jobRegistry, JobRepository jobRepository,\n\t\t\tBatchProperties batchProperties) {\n\t\tAssert.notNull(taskBatchProperties, \"taskBatchProperties must not be null\");\n\t\tAssert.notNull(batchProperties, \"batchProperties must not be null\");\n\t\tAssert.notEmpty(jobs, \"jobs must not be null nor empty\");\n\n\t\tthis.jobOperator = jobOperator;\n\t\tthis.jobs = jobs;\n\t\tthis.jobName = taskBatchProperties.getJobNames();\n\t\tthis.jobRegistry = jobRegistry;\n\t\tthis.taskBatchProperties = taskBatchProperties;\n\t\tif (StringUtils.hasText(batchProperties.getJob().getName())) {\n\t\t\tthis.jobName = batchProperties.getJob().getName();\n\t\t}\n\t\telse {\n\t\t\tthis.jobName = taskBatchProperties.getJobNames();\n\t\t}\n\t\tthis.order = taskBatchProperties.getApplicationRunnerOrder();\n\t\tthis.jobRepository = jobRepository;\n\t}\n\n\tpublic void setOrder(int order) {\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic TaskJobLauncherApplicationRunner getObject() {\n\t\tTaskJobLauncherApplicationRunner taskJobLauncherApplicationRunner = new TaskJobLauncherApplicationRunner(\n\t\t\t\tthis.jobOperator, this.jobRepository, this.taskBatchProperties);\n\t\ttaskJobLauncherApplicationRunner.setJobs(this.jobs);\n\t\tif (StringUtils.hasText(this.jobName)) {\n\t\t\ttaskJobLauncherApplicationRunner.setJobName(this.jobName);\n\t\t}\n\t\ttaskJobLauncherApplicationRunner.setJobRegistry(this.jobRegistry);\n\n\t\tif (this.order != null) {\n\t\t\ttaskJobLauncherApplicationRunner.setOrder(this.order);\n\t\t}\n\t\tif (this.applicationEventPublisher != null) {\n\t\t\ttaskJobLauncherApplicationRunner.setApplicationEventPublisher(this.applicationEventPublisher);\n\t\t}\n\t\treturn taskJobLauncherApplicationRunner;\n\t}\n\n\t@Override\n\tpublic Class<?> getObjectType() {\n\t\treturn TaskJobLauncherApplicationRunner.class;\n\t}\n\n\t@Override\n\tpublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {\n\t\tthis.applicationEventPublisher = applicationEventPublisher;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfiguration.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.configuration;\n\nimport java.util.List;\n\nimport org.springframework.batch.core.configuration.JobRegistry;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureBefore;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\n\n/**\n * Provides auto configuration for the\n * {@link org.springframework.cloud.task.batch.handler.TaskJobLauncherApplicationRunner}.\n *\n * @author Glenn Renfro\n */\n@AutoConfiguration\n@Conditional(JobLaunchCondition.class)\n@EnableConfigurationProperties(TaskBatchProperties.class)\n@AutoConfigureBefore(BatchAutoConfiguration.class)\npublic class TaskJobLauncherAutoConfiguration {\n\n\t@Autowired\n\tprivate TaskBatchProperties properties;\n\n\t@Bean\n\t@ConditionalOnClass(name = \"org.springframework.boot.batch.autoconfigure.JobLauncherApplicationRunner\")\n\tpublic TaskJobLauncherApplicationRunnerFactoryBean taskJobLauncherApplicationRunner(JobOperator jobLauncher,\n\t\t\tList<Job> jobs, JobRegistry jobRegistry, JobRepository jobRepository, BatchProperties batchProperties) {\n\t\tTaskJobLauncherApplicationRunnerFactoryBean taskJobLauncherApplicationRunnerFactoryBean;\n\t\ttaskJobLauncherApplicationRunnerFactoryBean = new TaskJobLauncherApplicationRunnerFactoryBean(jobLauncher, jobs,\n\t\t\t\tthis.properties, jobRegistry, jobRepository, batchProperties);\n\n\t\treturn taskJobLauncherApplicationRunnerFactoryBean;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Configuration classes for Spring Cloud Task Batch integration.\n */\npackage org.springframework.cloud.task.batch.configuration;\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherApplicationRunner.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.handler;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.Set;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.core.BatchStatus;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.JobExecutionException;\nimport org.springframework.batch.core.job.JobInstance;\nimport org.springframework.batch.core.job.parameters.InvalidJobParametersException;\nimport org.springframework.batch.core.job.parameters.JobParameter;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.job.parameters.JobParametersIncrementer;\nimport org.springframework.batch.core.launch.JobExecutionAlreadyRunningException;\nimport org.springframework.batch.core.launch.JobInstanceAlreadyCompleteException;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.launch.JobRestartException;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.batch.infrastructure.repeat.support.RepeatTemplate;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.batch.autoconfigure.JobExecutionEvent;\nimport org.springframework.boot.batch.autoconfigure.JobLauncherApplicationRunner;\nimport org.springframework.cloud.task.batch.configuration.TaskBatchProperties;\nimport org.springframework.cloud.task.listener.TaskException;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.core.task.TaskExecutor;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * {@link ApplicationRunner} to {@link JobOperator launch} Spring Batch jobs. Runs all\n * jobs in the surrounding context by default and throws an exception upon the first job\n * that returns an {@link BatchStatus} of FAILED if a {@link TaskExecutor} in the\n * {@link JobOperator} is not specified. If a {@link TaskExecutor} is specified in the\n * {@link JobOperator} then all Jobs are launched and an exception is thrown if one or\n * more of the jobs has an {@link BatchStatus} of FAILED. TaskJobLauncherApplicationRunner\n * can also be used to launch a specific job by providing a jobName. The\n * TaskJobLauncherApplicationRunner takes the place of the\n * {@link JobLauncherApplicationRunner} when it is in use.\n *\n * @author Glenn Renfro\n * @since 2.3.0\n */\npublic class TaskJobLauncherApplicationRunner extends JobLauncherApplicationRunner {\n\n\tprivate static final Log logger = LogFactory.getLog(TaskJobLauncherApplicationRunner.class);\n\n\tprivate final JobOperator taskJobOperator;\n\n\tprivate final JobRepository taskJobRepository;\n\n\tprivate final List<JobExecution> jobExecutionList = new ArrayList<>();\n\n\tprivate ApplicationEventPublisher taskApplicationEventPublisher;\n\n\tprivate final TaskBatchProperties taskBatchProperties;\n\n\t/**\n\t * Create a new {@link TaskJobLauncherApplicationRunner}.\n\t * @param jobOperator to launch jobs\n\t * @param jobRepository to check if a job instance exists with the given parameters\n\t * when running a job\n\t * @param taskBatchProperties the properties used to configure the\n\t * taskBatchProperties.\n\t */\n\tpublic TaskJobLauncherApplicationRunner(JobOperator jobOperator, JobRepository jobRepository,\n\t\t\tTaskBatchProperties taskBatchProperties) {\n\t\tsuper(jobOperator);\n\t\tthis.taskJobOperator = jobOperator;\n\t\tthis.taskJobRepository = jobRepository;\n\t\tthis.taskBatchProperties = taskBatchProperties;\n\t}\n\n\t@Override\n\tpublic void setApplicationEventPublisher(ApplicationEventPublisher publisher) {\n\t\tsuper.setApplicationEventPublisher(publisher);\n\t\tthis.taskApplicationEventPublisher = publisher;\n\t}\n\n\t@Override\n\tpublic void run(String... args) throws JobExecutionException {\n\t\tlogger.info(\"Running default command line with: \" + Arrays.asList(args));\n\t\tProperties properties = StringUtils.splitArrayElementsIntoProperties(args, \"=\");\n\t\tif (properties == null) {\n\t\t\tproperties = new Properties();\n\t\t}\n\t\tlaunchJobFromProperties(properties);\n\t\tmonitorJobExecutions();\n\t}\n\n\t@Override\n\tprotected void execute(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException,\n\t\t\tJobRestartException, JobInstanceAlreadyCompleteException, InvalidJobParametersException {\n\t\tString jobName = job.getName();\n\t\tJobParameters parameters = jobParameters;\n\t\tboolean jobInstanceExists = this.taskJobRepository.getJobInstance(job.getName(), jobParameters) != null;\n\t\tif (jobInstanceExists) {\n\t\t\tJobExecution lastJobExecution = this.taskJobRepository.getLastJobExecution(jobName, jobParameters);\n\t\t\tif (lastJobExecution != null && isStoppedOrFailed(lastJobExecution) && job.isRestartable()) {\n\t\t\t\t// Retry a failed or stopped execution with previous parameters\n\t\t\t\tJobParameters previousParameters = lastJobExecution.getJobParameters();\n\t\t\t\t/*\n\t\t\t\t * remove Non-identifying parameters from the previous execution's\n\t\t\t\t * parameters since there is no way to remove them programmatically. If\n\t\t\t\t * they are required (or need to be modified) on a restart, they need to\n\t\t\t\t * be (re)specified.\n\t\t\t\t */\n\t\t\t\tJobParameters previousIdentifyingParameters = removeNonIdentifying(previousParameters);\n\t\t\t\t// merge additional parameters with previous ones (overriding those with\n\t\t\t\t// the same key)\n\t\t\t\tparameters = merge(previousIdentifyingParameters, jobParameters);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tJobParametersIncrementer incrementer = job.getJobParametersIncrementer();\n\t\t\tif (incrementer != null) {\n\t\t\t\tJobParameters nextParameters = getNextJobParameters(job, new HashSet<>(jobParameters.parameters()),\n\t\t\t\t\t\tthis.taskJobRepository);\n\t\t\t\tparameters = merge(nextParameters, jobParameters);\n\t\t\t}\n\t\t}\n\t\tJobExecution execution = this.taskJobOperator.start(job, parameters);\n\t\tif (this.taskApplicationEventPublisher != null) {\n\t\t\tthis.taskApplicationEventPublisher.publishEvent(new JobExecutionEvent(execution));\n\t\t}\n\t\tthis.jobExecutionList.add(execution);\n\t\tif (execution.getStatus().equals(BatchStatus.FAILED)) {\n\t\t\tthrowJobFailedException(Collections.singletonList(execution));\n\t\t}\n\t}\n\n\tprivate void monitorJobExecutions() {\n\t\tRepeatTemplate template = new RepeatTemplate();\n\n\t\ttemplate.iterate(context -> {\n\n\t\t\tList<JobExecution> failedJobExecutions = new ArrayList<>();\n\t\t\tfor (JobExecution jobExecution : this.jobExecutionList) {\n\t\t\t\tBatchStatus batchStatus = getCurrentBatchStatus(jobExecution);\n\t\t\t\tif (batchStatus.isRunning()) {\n\t\t\t\t\tThread.sleep(this.taskBatchProperties.getFailOnJobFailurePollInterval());\n\t\t\t\t\treturn RepeatStatus.CONTINUABLE;\n\t\t\t\t}\n\t\t\t\tif (batchStatus.equals(BatchStatus.FAILED)) {\n\t\t\t\t\tfailedJobExecutions.add(jobExecution);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (failedJobExecutions.size() > 0) {\n\t\t\t\tthrowJobFailedException(failedJobExecutions);\n\t\t\t}\n\t\t\treturn RepeatStatus.FINISHED;\n\t\t});\n\t}\n\n\tprivate BatchStatus getCurrentBatchStatus(JobExecution jobExecution) {\n\t\tif (jobExecution.getStatus().isRunning()) {\n\t\t\treturn this.taskJobRepository.getJobExecution(jobExecution.getId()).getStatus();\n\t\t}\n\t\treturn jobExecution.getStatus();\n\t}\n\n\tprivate void throwJobFailedException(List<JobExecution> failedJobExecutions) {\n\t\tStringBuilder message = new StringBuilder(\"The following Jobs have failed: \\n\");\n\t\tfor (JobExecution failedJobExecution : failedJobExecutions) {\n\t\t\tmessage.append(String.format(\n\t\t\t\t\t\"Job %s failed during \" + \"execution for job instance id %s with jobExecutionId of %s \\n\",\n\t\t\t\t\tfailedJobExecution.getJobInstance().getJobName(), failedJobExecution.getId(),\n\t\t\t\t\tfailedJobExecution.getId()));\n\t\t}\n\n\t\tlogger.error(message);\n\n\t\tthrow new TaskException(message.toString());\n\n\t}\n\n\tprivate JobParameters removeNonIdentifying(JobParameters parameters) {\n\t\tSet<JobParameter<?>> parameterMap = parameters.parameters();\n\t\tSet<JobParameter<?>> copy = new HashSet<>();\n\n\t\tfor (JobParameter<?> parameter : parameterMap) {\n\t\t\tif (parameter.identifying()) {\n\t\t\t\tcopy.add(parameter);\n\t\t\t}\n\t\t}\n\n\t\treturn new JobParameters(copy);\n\t}\n\n\tprivate boolean isStoppedOrFailed(JobExecution execution) {\n\t\tBatchStatus status = execution.getStatus();\n\t\treturn (status == BatchStatus.STOPPED || status == BatchStatus.FAILED);\n\t}\n\n\tprivate JobParameters merge(JobParameters parameters, JobParameters additionals) {\n\t\tMap<String, JobParameter<?>> merged = new HashMap<>();\n\t\t// Add base parameters\n\t\tfor (JobParameter<?> param : parameters.parameters()) {\n\t\t\tmerged.put(param.name(), param);\n\t\t}\n\t\t// Override with additionals\n\t\tfor (JobParameter<?> param : additionals.parameters()) {\n\t\t\tmerged.put(param.name(), param);\n\t\t}\n\t\treturn new JobParameters(new HashSet<>(merged.values()));\n\t}\n\n\t/**\n\t * Initializes the {@link JobParameters} based on the state of the {@link Job}. This\n\t * should be called after all parameters have been entered into the builder. All\n\t * parameters already set on this builder instance are appended to those retrieved\n\t * from the job incrementer, overriding any with the same key (this is the same\n\t * behavior as\n\t * {@link org.springframework.batch.core.launch.support.CommandLineJobRunner} with the\n\t * {@code -next} option and\n\t * {@link org.springframework.batch.core.launch.JobOperator#startNextInstance(String)}).\n\t * @param job The job for which the {@link JobParameters} are being constructed.\n\t * @return a reference to this object.\n\t *\n\t * @since 4.0\n\t */\n\tpublic JobParameters getNextJobParameters(Job job, Set<JobParameter<?>> parameterMap,\n\t\t\tJobRepository taskJobRepository) {\n\t\tAssert.notNull(job, \"Job must not be null\");\n\t\tAssert.notNull(job.getJobParametersIncrementer(),\n\t\t\t\t\"No job parameters incrementer found for job=\" + job.getName());\n\n\t\tString name = job.getName();\n\t\tJobParameters nextParameters;\n\t\tJobInstance lastInstance = taskJobRepository.getLastJobInstance(name);\n\t\tJobParametersIncrementer incrementer = job.getJobParametersIncrementer();\n\t\tif (lastInstance == null) {\n\t\t\t// Start from a completely clean sheet\n\t\t\tnextParameters = incrementer.getNext(new JobParameters());\n\t\t}\n\t\telse {\n\t\t\tJobExecution previousExecution = taskJobRepository.getLastJobExecution(lastInstance);\n\t\t\tif (previousExecution == null) {\n\t\t\t\t// Normally this will not happen - an instance exists with no executions\n\t\t\t\tnextParameters = incrementer.getNext(new JobParameters());\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnextParameters = incrementer.getNext(previousExecution.getJobParameters());\n\t\t\t}\n\t\t}\n\n\t\t// start with parameters from the incrementer\n\t\tSet<JobParameter<?>> nextParametersMap = new HashSet<>(nextParameters.parameters());\n\t\t// append new parameters (overriding those with the same key)\n\t\tnextParametersMap.addAll(parameterMap);\n\t\tparameterMap = nextParametersMap;\n\t\treturn new JobParameters(parameterMap);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Handler components for Spring Cloud Task Batch integration.\n */\npackage org.springframework.cloud.task.batch.handler;\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/listener/TaskBatchDao.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.cloud.task.repository.TaskExecution;\n\n/**\n * Maintains the association between a {@link TaskExecution} and a {@link JobExecution}\n * executed within it.\n *\n * @author Michael Minella\n */\npublic interface TaskBatchDao {\n\n\t/**\n\t * Saves the relationship between a task execution and a job execution.\n\t * @param taskExecution task execution\n\t * @param jobExecution job execution\n\t */\n\tvoid saveRelationship(TaskExecution taskExecution, JobExecution jobExecution);\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/listener/TaskBatchExecutionListener.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.listener.JobExecutionListener;\nimport org.springframework.cloud.task.listener.TaskExecutionListener;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * Responsible for storing the relationship between a Spring Batch job and the Spring\n * Cloud task it was executed within.\n *\n * @author Michael Minella\n */\npublic class TaskBatchExecutionListener implements JobExecutionListener, Ordered, TaskExecutionListener {\n\n\tprivate static final Log logger = LogFactory.getLog(TaskBatchExecutionListener.class);\n\n\tprivate TaskExecution taskExecution;\n\n\tprivate final TaskBatchDao taskBatchDao;\n\n\t/**\n\t * @param taskBatchDao dao used to persist the relationship. Must not be null\n\t */\n\tpublic TaskBatchExecutionListener(TaskBatchDao taskBatchDao) {\n\t\tAssert.notNull(taskBatchDao, \"A TaskBatchDao is required\");\n\n\t\tthis.taskBatchDao = taskBatchDao;\n\t}\n\n\t@Override\n\tpublic void onTaskStartup(TaskExecution taskExecution) {\n\t\tthis.taskExecution = taskExecution;\n\t}\n\n\t@Override\n\tpublic void beforeJob(JobExecution jobExecution) {\n\t\tif (this.taskExecution == null) {\n\t\t\tlogger.warn(\"This job was executed outside the scope of a task but still used the task listener.\");\n\t\t}\n\t\telse {\n\t\t\tlogger.info(String.format(\"The job execution id %s was run within the task execution %s\",\n\t\t\t\t\tjobExecution.getId(), this.taskExecution.getExecutionId()));\n\t\t\tthis.taskBatchDao.saveRelationship(this.taskExecution, jobExecution);\n\t\t}\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn Ordered.HIGHEST_PRECEDENCE;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/listener/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Listener components for Spring Cloud Task Batch integration.\n */\npackage org.springframework.cloud.task.batch.listener;\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/listener/support/JdbcTaskBatchDao.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.cloud.task.batch.listener.TaskBatchDao;\nimport org.springframework.cloud.task.configuration.TaskProperties;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.jdbc.core.JdbcOperations;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * JDBC based implementation of the {@link TaskBatchDao}. Intended to be used in\n * conjunction with the JDBC based\n * {@link org.springframework.cloud.task.repository.TaskRepository}\n *\n * @author Michael Minella\n * @author Glenn Renfro\n */\npublic class JdbcTaskBatchDao implements TaskBatchDao {\n\n\tprivate static final String INSERT_STATEMENT = \"INSERT INTO %PREFIX%TASK_BATCH (TASK_EXECUTION_ID, JOB_EXECUTION_ID) VALUES (?, ?)\";\n\n\tprivate String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX;\n\n\tprivate final JdbcOperations jdbcTemplate;\n\n\t/**\n\t * Initializes the JdbcTaskBatchDao.\n\t * @param dataSource {@link DataSource} where the task batch table resides.\n\t * @param tablePrefix the table prefix to use for this dao.\n\t */\n\tpublic JdbcTaskBatchDao(DataSource dataSource, String tablePrefix) {\n\t\tthis(dataSource);\n\t\tAssert.hasText(tablePrefix, \"tablePrefix must not be null nor empty.\");\n\t\tthis.tablePrefix = tablePrefix;\n\t}\n\n\t/**\n\t * Initializes the JdbcTaskBatchDao and defaults the table prefix to\n\t * {@link TaskProperties#DEFAULT_TABLE_PREFIX}.\n\t * @param dataSource {@link DataSource} where the task batch table resides.\n\t */\n\tpublic JdbcTaskBatchDao(DataSource dataSource) {\n\t\tAssert.notNull(dataSource, \"A dataSource is required\");\n\n\t\tthis.jdbcTemplate = new JdbcTemplate(dataSource);\n\t}\n\n\t@Override\n\tpublic void saveRelationship(TaskExecution taskExecution, JobExecution jobExecution) {\n\t\tAssert.notNull(taskExecution, \"A taskExecution is required\");\n\t\tAssert.notNull(jobExecution, \"A jobExecution is required\");\n\t\tthis.jdbcTemplate.update(getQuery(INSERT_STATEMENT), taskExecution.getExecutionId(), jobExecution.getId());\n\t}\n\n\tprivate String getQuery(String base) {\n\t\treturn StringUtils.replace(base, \"%PREFIX%\", this.tablePrefix);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/listener/support/MapTaskBatchDao.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.cloud.task.batch.listener.TaskBatchDao;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.util.Assert;\n\n/**\n * Map implementation of the {@link TaskBatchDao}.\n * <p>\n * This is intended for testing purposes only!\n * </p>\n *\n * @author Michael Minella\n */\npublic class MapTaskBatchDao implements TaskBatchDao {\n\n\tprivate Map<Long, Set<Long>> relationships;\n\n\tpublic MapTaskBatchDao(Map<Long, Set<Long>> relationships) {\n\t\tAssert.notNull(relationships, \"Relationships must not be null\");\n\t\tthis.relationships = relationships;\n\t}\n\n\t@Override\n\tpublic void saveRelationship(TaskExecution taskExecution, JobExecution jobExecution) {\n\t\tAssert.notNull(taskExecution, \"A taskExecution is required\");\n\t\tAssert.notNull(jobExecution, \"A jobExecution is required\");\n\n\t\tif (this.relationships.containsKey(taskExecution.getExecutionId())) {\n\t\t\tthis.relationships.get(taskExecution.getExecutionId()).add(jobExecution.getId());\n\t\t}\n\t\telse {\n\t\t\tTreeSet<Long> jobExecutionIds = new TreeSet<>();\n\t\t\tjobExecutionIds.add(jobExecution.getId());\n\n\t\t\tthis.relationships.put(taskExecution.getExecutionId(), jobExecutionIds);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/listener/support/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes for Spring Cloud Task Batch listener implementations.\n */\npackage org.springframework.cloud.task.batch.listener.support;\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n\t\"properties\": [\n\t\t{\n\t\t\t\"defaultValue\": true,\n\t\t\t\"name\": \"spring.cloud.task.batch.listener.enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task will be linked to the batch jobs that are run.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t},\n\t\t{\n\t\t\t\"defaultValue\": false,\n\t\t\t\"name\": \"spring.cloud.task.batch.fail-on-job-failure\",\n\t\t\t\"description\": \"This property is used to determine if a task app should return with a non zero exit code if a batch job fails.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t},\n\t\t{\n\t\t\t\"defaultValue\": true,\n\t\t\t\"name\": \"spring.cloud.task.batch.events.enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task should listen for batch events.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t},\n\t\t{\n\t\t\t\"defaultValue\": true,\n\t\t\t\"name\": \"spring.cloud.task.batch.events.chunk.enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task should listen for batch chunk events.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t},\n\t\t{\n\t\t\t\"defaultValue\": true,\n\t\t\t\"name\": \"spring.cloud.task.batch.events.item-process.enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task should listen for batch item processed events.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t},\n\t\t{\n\t\t\t\"defaultValue\": true,\n\t\t\t\"name\": \"spring.cloud.task.batch.events.item-read.enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task should listen for batch item read events.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t},\n\t\t{\n\t\t\t\"defaultValue\": true,\n\t\t\t\"name\": \"spring.cloud.task.batch.events.item-write.enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task should listen for batch item write events.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t},\n\t\t{\n\t\t\t\"defaultValue\": true,\n\t\t\t\"name\": \"spring.cloud.task.batch.events.job-execution.enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task should listen for batch job execution events.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t},\n\t\t{\n\t\t\t\"defaultValue\": true,\n\t\t\t\"name\": \"spring.cloud.task.batch.events.skip.enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task should listen for batch skip events.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t},\n\t\t{\n\t\t\t\"defaultValue\": true,\n\t\t\t\"name\": \"spring.cloud.task.batch.events.step-execution.enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task should listen for batch step execution events.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration\norg.springframework.cloud.task.batch.configuration.TaskJobLauncherAutoConfiguration\n"
  },
  {
    "path": "spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskBatchTest.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.configuration;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\n\n/**\n * Contains the common configurations to run a unit test for the task batch features of\n * SCT.\n *\n * @author Glenn Renfro\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@ImportAutoConfiguration\npublic @interface TaskBatchTest {\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.configuration;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.configuration.JobRegistry;\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.configuration.support.MapJobRegistry;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.JobLauncherApplicationRunner;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.test.context.assertj.AssertableApplicationContext;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.batch.handler.TaskJobLauncherApplicationRunner;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n */\npublic class TaskJobLauncherAutoConfigurationTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(BatchAutoConfiguration.class, EmbeddedDataSourceConfiguration.class))\n\t\t.withUserConfiguration(TestJobConfiguration.class);\n\n\t@Test\n\tpublic void testAutoBuiltDataSourceWithTaskJobLauncherCLR() {\n\t\tthis.contextRunner.withPropertyValues(\"spring.cloud.task.batch.fail-on-job-failure=true\").run(context -> {\n\t\t\tassertThat(context).hasSingleBean(TaskJobLauncherApplicationRunner.class);\n\t\t\tassertThat(context.getBean(TaskJobLauncherApplicationRunner.class).getOrder()).isEqualTo(0);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testAutoBuiltDataSourceWithTaskJobLauncherCLROrder() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cloud.task.batch.fail-on-job-failure=true\",\n\t\t\t\t\t\"spring.cloud.task.batch.applicationRunnerOrder=100\")\n\t\t\t.run(context -> {\n\t\t\t\tassertThat(context.getBean(TaskJobLauncherApplicationRunner.class).getOrder()).isEqualTo(100);\n\t\t\t});\n\t}\n\n\t@Test\n\tpublic void testAutoBuiltDataSourceWithBatchJobNames() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cloud.task.batch.fail-on-job-failure=true\", \"spring.batch.job.name=job1\",\n\t\t\t\t\t\"spring.cloud.task.batch.jobName=foobar\")\n\t\t\t.run(context -> {\n\t\t\t\tvalidateJobNames(context, \"job1\");\n\t\t\t});\n\t}\n\n\t@Test\n\tpublic void testAutoBuiltDataSourceWithTaskBatchJobNames() {\n\t\tthis.contextRunner\n\t\t\t.withPropertyValues(\"spring.cloud.task.batch.fail-on-job-failure=true\",\n\t\t\t\t\t\"spring.cloud.task.batch.jobNames=job1,job2\")\n\t\t\t.run(context -> {\n\t\t\t\tvalidateJobNames(context, \"job1,job2\");\n\t\t\t});\n\t}\n\n\tprivate void validateJobNames(AssertableApplicationContext context, String jobNames) throws Exception {\n\t\tJobLauncherApplicationRunner jobLauncherApplicationRunner = context\n\t\t\t.getBean(TaskJobLauncherApplicationRunner.class);\n\n\t\tObject names = ReflectionTestUtils.getField(jobLauncherApplicationRunner, \"jobName\");\n\t\tassertThat(names).isEqualTo(jobNames);\n\t}\n\n\t@Test\n\tpublic void testAutoBuiltDataSourceWithTaskJobLauncherCLRDisabled() {\n\t\tthis.contextRunner.run(context -> {\n\t\t\t// assertThat(context).hasSingleBean(JobLauncherApplicationRunner.class);\n\t\t\tassertThat(context).doesNotHaveBean(TaskJobLauncherApplicationRunner.class);\n\t\t});\n\t}\n\n\t@Configuration\n\t@EnableAutoConfiguration\n\t@EnableBatchProcessing\n\tstatic class TestJobConfiguration {\n\n\t\t@Bean\n\t\tpublic Job job(JobRepository jobRepository, PlatformTransactionManager transactionManager) {\n\t\t\treturn new JobBuilder(\"job\", jobRepository)\n\t\t\t\t.start(new StepBuilder(\"step1\", jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}, transactionManager).build())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tJobRegistry jobRegistry() {\n\t\t\treturn new MapJobRegistry();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherApplicationRunnerCoreTests.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.handler;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.JobExecutionException;\nimport org.springframework.batch.core.job.JobInstance;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.job.builder.SimpleJobBuilder;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.job.parameters.JobParametersBuilder;\nimport org.springframework.batch.core.job.parameters.RunIdIncrementer;\nimport org.springframework.batch.core.launch.JobOperator;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.Step;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.core.step.tasklet.Tasklet;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.boot.transaction.autoconfigure.TransactionAutoConfiguration;\nimport org.springframework.cloud.task.batch.configuration.TaskBatchProperties;\nimport org.springframework.cloud.task.listener.TaskException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;\n\n/**\n * @author Glenn Renfro\n */\npublic class TaskJobLauncherApplicationRunnerCoreTests {\n\n\tprivate final ApplicationContextRunner contextRunner = new ApplicationContextRunner()\n\t\t.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class,\n\t\t\t\tDataSourceTransactionManagerAutoConfiguration.class))\n\t\t.withUserConfiguration(BatchConfiguration.class);\n\n\t@Test\n\tvoid basicExecution() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tJobLauncherApplicationRunnerContext jobLauncherContext = new JobLauncherApplicationRunnerContext(context);\n\t\t\tjobLauncherContext.executeJob(new JobParameters());\n\t\t\tassertThat(jobLauncherContext.jobInstances()).hasSize(1);\n\t\t\tjobLauncherContext.executeJob(new JobParametersBuilder().addLong(\"id\", 1L).toJobParameters());\n\t\t\tassertThat(jobLauncherContext.jobInstances()).hasSize(2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid incrementExistingExecution() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tJobLauncherApplicationRunnerContext jobLauncherContext = new JobLauncherApplicationRunnerContext(context);\n\t\t\tJob job = jobLauncherContext.configureJob().incrementer(new RunIdIncrementer()).build();\n\n\t\t\tjobLauncherContext.runner.execute(job, new JobParameters());\n\t\t\tjobLauncherContext.runner.execute(job, new JobParameters());\n\t\t\tassertThat(jobLauncherContext.jobInstances()).hasSize(2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid runDifferentInstances() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tPlatformTransactionManager transactionManager = context.getBean(PlatformTransactionManager.class);\n\t\t\tJobLauncherApplicationRunnerContext jobLauncherContext = new JobLauncherApplicationRunnerContext(context);\n\t\t\tJob job = jobLauncherContext.jobBuilder()\n\t\t\t\t.start(jobLauncherContext.stepBuilder().tasklet(throwingTasklet(), transactionManager).build())\n\t\t\t\t.build();\n\t\t\t// start a job instance\n\t\t\tJobParameters jobParameters = new JobParametersBuilder().addString(\"name\", \"foo\").toJobParameters();\n\t\t\trunFailedJob(jobLauncherContext, job, jobParameters);\n\t\t\tassertThat(jobLauncherContext.jobInstances()).hasSize(1);\n\t\t\t// start a different job instance\n\t\t\tJobParameters otherJobParameters = new JobParametersBuilder().addString(\"name\", \"bar\").toJobParameters();\n\t\t\trunFailedJob(jobLauncherContext, job, otherJobParameters);\n\n\t\t\tassertThat(jobLauncherContext.jobInstances()).hasSize(2);\n\t\t});\n\t}\n\n\t@Test\n\tvoid retryFailedExecutionOnNonRestartableJob() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tPlatformTransactionManager transactionManager = context.getBean(PlatformTransactionManager.class);\n\t\t\tJobLauncherApplicationRunnerContext jobLauncherContext = new JobLauncherApplicationRunnerContext(context);\n\t\t\tJob job = jobLauncherContext.jobBuilder()\n\t\t\t\t.preventRestart()\n\t\t\t\t.start(jobLauncherContext.stepBuilder().tasklet(throwingTasklet(), transactionManager).build())\n\t\t\t\t.incrementer(new RunIdIncrementer())\n\t\t\t\t.build();\n\t\t\trunFailedJob(jobLauncherContext, job, new JobParameters());\n\n\t\t\t// A failed job that is not restartable does not re-use the job params of\n\t\t\t// the last execution, but creates a new job instance when running it again.\n\t\t\tassertThat(jobLauncherContext.jobInstances()).hasSize(1);\n\t\t\tassertThatExceptionOfType(TaskException.class).isThrownBy(() -> {\n\t\t\t\t// try to re-run a failed execution\n\t\t\t\t// In this case the change from the previous behavior is that a new job\n\t\t\t\t// instance is created\n\t\t\t\t// https://github.com/spring-projects/spring-batch/issues/4910\n\t\t\t\tjobLauncherContext.runner.execute(job,\n\t\t\t\t\t\tnew JobParametersBuilder().addLong(\"run.id\", 1L).toJobParameters());\n\t\t\t}).withMessageContaining(\"Job job failed during execution for job instance id 2 with jobExecutionId of 2 \");\n\t\t});\n\t}\n\n\t@Test\n\tvoid retryFailedExecutionWithNonIdentifyingParameters() {\n\t\tthis.contextRunner.run((context) -> {\n\t\t\tPlatformTransactionManager transactionManager = context.getBean(PlatformTransactionManager.class);\n\t\t\tJobLauncherApplicationRunnerContext jobLauncherContext = new JobLauncherApplicationRunnerContext(context);\n\t\t\tJob job = jobLauncherContext.jobBuilder()\n\t\t\t\t.start(jobLauncherContext.stepBuilder().tasklet(throwingTasklet(), transactionManager).build())\n\t\t\t\t.incrementer(new RunIdIncrementer())\n\t\t\t\t.build();\n\t\t\tJobParameters jobParameters = new JobParametersBuilder().addLong(\"id\", 1L, false)\n\t\t\t\t.addLong(\"foo\", 2L, false)\n\t\t\t\t.toJobParameters();\n\t\t\trunFailedJob(jobLauncherContext, job, jobParameters);\n\t\t\tassertThat(jobLauncherContext.jobInstances()).hasSize(1);\n\t\t\t// try to re-run a failed execution with non identifying parameters\n\t\t\t// Updated to expect a new 2 instances are created because of this change\n\t\t\t// https://github.com/spring-projects/spring-batch/issues/4910\n\t\t\trunFailedJob(jobLauncherContext, job,\n\t\t\t\t\tnew JobParametersBuilder(jobParameters).addLong(\"run.id\", 1L).toJobParameters());\n\t\t\tassertThat(jobLauncherContext.jobInstances()).hasSize(2);\n\t\t});\n\t}\n\n\tprivate Tasklet throwingTasklet() {\n\t\treturn (contribution, chunkContext) -> {\n\t\t\tthrow new RuntimeException(\"Planned\");\n\t\t};\n\t}\n\n\tprivate void runFailedJob(JobLauncherApplicationRunnerContext jobLauncherContext, Job job,\n\t\t\tJobParameters jobParameters) throws Exception {\n\t\tboolean isExceptionThrown = false;\n\t\ttry {\n\t\t\tjobLauncherContext.runner.execute(job, jobParameters);\n\t\t}\n\t\tcatch (TaskException taskException) {\n\t\t\tisExceptionThrown = true;\n\t\t}\n\t\tassertThat(isExceptionThrown).isTrue();\n\t}\n\n\tstatic class JobLauncherApplicationRunnerContext {\n\n\t\tprivate final TaskJobLauncherApplicationRunner runner;\n\n\t\tprivate final JobRepository jobRepository;\n\n\t\tprivate final JobBuilder jobBuilder;\n\n\t\tprivate final Job job;\n\n\t\tprivate final StepBuilder stepBuilder;\n\n\t\tprivate final Step step;\n\n\t\tJobLauncherApplicationRunnerContext(ApplicationContext context) {\n\t\t\tJobOperator jobOperator = context.getBean(JobOperator.class);\n\t\t\tjobRepository = context.getBean(JobRepository.class);\n\t\t\tPlatformTransactionManager transactionManager = context.getBean(PlatformTransactionManager.class);\n\t\t\tthis.stepBuilder = new StepBuilder(\"step\", jobRepository);\n\t\t\tthis.step = this.stepBuilder.tasklet((contribution, chunkContext) -> null, transactionManager).build();\n\t\t\tthis.jobBuilder = new JobBuilder(\"job\", jobRepository);\n\t\t\tthis.job = this.jobBuilder.start(this.step).build();\n\t\t\tthis.runner = new TaskJobLauncherApplicationRunner(jobOperator, jobRepository, new TaskBatchProperties());\n\t\t}\n\n\t\tList<JobInstance> jobInstances() {\n\t\t\treturn this.jobRepository.getJobInstances(\"job\", 0, 100);\n\t\t}\n\n\t\tvoid executeJob(JobParameters jobParameters) throws JobExecutionException {\n\t\t\tthis.runner.execute(this.job, jobParameters);\n\t\t}\n\n\t\tJobBuilder jobBuilder() {\n\t\t\treturn this.jobBuilder;\n\t\t}\n\n\t\tStepBuilder stepBuilder() {\n\t\t\treturn this.stepBuilder;\n\t\t}\n\n\t\tSimpleJobBuilder configureJob() {\n\t\t\treturn this.jobBuilder.start(this.step);\n\t\t}\n\n\t}\n\n\t@EnableBatchProcessing\n\t@EnableJdbcJobRepository\n\t@Configuration(proxyBeanMethods = false)\n\tstatic class BatchConfiguration {\n\n\t\tprivate final DataSource dataSource;\n\n\t\tprotected BatchConfiguration(DataSource dataSource) {\n\t\t\tthis.dataSource = dataSource;\n\t\t}\n\n\t\t@Bean\n\t\tDataSourceScriptDatabaseInitializer batchDataSourceInitializer() {\n\t\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\t\tsettings.setSchemaLocations(Arrays.asList(\"classpath:org/springframework/batch/core/schema-h2.sql\"));\n\t\t\treturn new DataSourceScriptDatabaseInitializer(this.dataSource, settings);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherApplicationRunnerTests.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.handler;\n\nimport java.util.Arrays;\nimport java.util.Set;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.function.Executable;\n\nimport org.springframework.batch.core.configuration.JobRegistry;\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.configuration.annotation.EnableJdbcJobRepository;\nimport org.springframework.batch.core.configuration.support.MapJobRegistry;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchProperties;\nimport org.springframework.boot.batch.autoconfigure.JobExecutionEvent;\nimport org.springframework.boot.batch.autoconfigure.JobLauncherApplicationRunner;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer;\nimport org.springframework.boot.sql.init.DatabaseInitializationSettings;\nimport org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration;\nimport org.springframework.cloud.task.batch.configuration.TaskJobLauncherAutoConfiguration;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.configuration.SingleTaskConfiguration;\nimport org.springframework.cloud.task.listener.TaskException;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.stereotype.Component;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * @author Glenn Renfro\n */\npublic class TaskJobLauncherApplicationRunnerTests {\n\n\tprivate static final String DEFAULT_ERROR_MESSAGE = \"Job jobA failed during execution for job instance id 1 with jobExecutionId of 1\";\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testTaskJobLauncherCLRSuccessFail() {\n\t\tString[] enabledArgs = new String[] { \"--spring.cloud.task.batch.failOnJobFailure=true\" };\n\t\tvalidateForFail(DEFAULT_ERROR_MESSAGE, TaskJobLauncherApplicationRunnerTests.JobWithFailureConfiguration.class,\n\t\t\t\tenabledArgs);\n\t}\n\n\t/**\n\t * Verifies that the task will return an exit code other than zero if the job fails\n\t * with the EnableTask annotation.\n\t */\n\t@Disabled(\"The task repository is not getting populated.\")\n\t@Test\n\tpublic void testTaskJobLauncherCLRSuccessFailWithAnnotation() {\n\t\tString[] enabledArgs = new String[] { \"--spring.cloud.task.batch.failOnJobFailure=true\" };\n\t\tvalidateForFail(DEFAULT_ERROR_MESSAGE,\n\t\t\t\tTaskJobLauncherApplicationRunnerTests.JobWithFailureAnnotatedConfiguration.class, enabledArgs);\n\t}\n\n\t@Test\n\tpublic void testTaskJobLauncherCLRSuccessFailWithTaskExecutor() {\n\t\tString[] enabledArgs = new String[] { \"--spring.cloud.task.batch.failOnJobFailure=true\",\n\t\t\t\t\"--spring.cloud.task.batch.failOnJobFailurePollInterval=500\" };\n\t\tvalidateForFail(DEFAULT_ERROR_MESSAGE,\n\t\t\t\tTaskJobLauncherApplicationRunnerTests.JobWithFailureTaskExecutorConfiguration.class, enabledArgs);\n\t}\n\n\t@Test\n\tpublic void testNoTaskJobLauncher() {\n\t\tString[] enabledArgs = new String[] { \"--spring.cloud.task.batch.failOnJobFailure=true\",\n\t\t\t\t\"--spring.cloud.task.batch.failOnJobFailurePollInterval=500\", \"--spring.batch.job.enabled=false\" };\n\t\tthis.applicationContext = SpringApplication\n\t\t\t.run(new Class[] { TaskJobLauncherApplicationRunnerTests.JobWithFailureConfiguration.class }, enabledArgs);\n\t\tJobRepository jobRepository = this.applicationContext.getBean(JobRepository.class);\n\t\tassertThat(jobRepository.getJobNames().size()).isEqualTo(0);\n\t}\n\n\t@Test\n\tpublic void testTaskJobLauncherPickOneJob() {\n\t\tString[] enabledArgs = new String[] { \"--spring.cloud.task.batch.fail-on-job-failure=true\",\n\t\t\t\t\"--spring.cloud.task.batch.jobNames=jobSucceed\" };\n\t\tboolean isExceptionThrown = false;\n\t\ttry {\n\t\t\tthis.applicationContext = SpringApplication.run(\n\t\t\t\t\tnew Class[] { TaskJobLauncherApplicationRunnerTests.JobWithFailureConfiguration.class },\n\t\t\t\t\tenabledArgs);\n\t\t}\n\t\tcatch (IllegalStateException exception) {\n\t\t\tisExceptionThrown = true;\n\t\t}\n\t\tassertThat(isExceptionThrown).isFalse();\n\t\tvalidateContext();\n\t}\n\n\t@Test\n\tpublic void testApplicationRunnerSetToFalse() {\n\t\tString[] enabledArgs = new String[] {};\n\t\tthis.applicationContext = SpringApplication\n\t\t\t.run(new Class[] { TaskJobLauncherApplicationRunnerTests.JobConfiguration.class }, enabledArgs);\n\t\tvalidateContext();\n\t\tassertThat(this.applicationContext.getBean(JobLauncherApplicationRunner.class)).isNotNull();\n\n\t\tExecutable executable = () -> this.applicationContext.getBean(TaskJobLauncherApplicationRunner.class);\n\n\t\tassertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(executable::execute)\n\t\t\t.withMessage(\"No qualifying bean of type \"\n\t\t\t\t\t+ \"'org.springframework.cloud.task.batch.handler.TaskJobLauncherApplicationRunner' available\");\n\t\tvalidateContext();\n\t}\n\n\tprivate void validateContext() {\n\t\tTaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);\n\n\t\tPage<TaskExecution> page = taskExplorer.findTaskExecutionsByName(\"application\", PageRequest.of(0, 1));\n\n\t\tSet<Long> jobExecutionIds = taskExplorer\n\t\t\t.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId());\n\n\t\tassertThat(jobExecutionIds.size()).isEqualTo(1);\n\t\tassertThat(taskExplorer.getTaskExecution(jobExecutionIds.iterator().next()).getExecutionId()).isEqualTo(1);\n\n\t\tJobExecutionEventListener listener = this.applicationContext.getBean(JobExecutionEventListener.class);\n\t\tassertThat(listener.getEventCounter()).isEqualTo(1);\n\t}\n\n\tprivate void validateForFail(String errorMessage, Class<?> clazz, String[] enabledArgs) {\n\t\tExecutable executable = () -> this.applicationContext = SpringApplication\n\t\t\t.run(new Class[] { clazz, PropertyPlaceholderAutoConfiguration.class }, enabledArgs);\n\n\t\tassertThatExceptionOfType(TaskException.class).isThrownBy(executable::execute)\n\t\t\t.withMessageContaining(errorMessage);\n\t}\n\n\t@Component\n\tprivate static final class JobExecutionEventListener implements ApplicationListener<JobExecutionEvent> {\n\n\t\tprivate int eventCounter = 0;\n\n\t\t@Override\n\t\tpublic void onApplicationEvent(JobExecutionEvent event) {\n\t\t\teventCounter++;\n\t\t}\n\n\t\tpublic int getEventCounter() {\n\t\t\treturn eventCounter;\n\t\t}\n\n\t}\n\n\t@EnableTask\n\t@Import({ JobExecutionEventListener.class })\n\t@EnableAutoConfiguration(exclude = TaskJobLauncherAutoConfiguration.class)\n\t@EnableBatchProcessing\n\t@Configuration\n\tpublic static class JobConfiguration {\n\n\t\t@Bean\n\t\tpublic Job job(JobRepository jobRepository, PlatformTransactionManager transactionManager) {\n\t\t\treturn new JobBuilder(\"job\", jobRepository)\n\t\t\t\t.start(new StepBuilder(\"step1\", jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}, transactionManager).build())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic JobRegistry jobRegistry() {\n\t\t\treturn new MapJobRegistry();\n\t\t}\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@Import(JobExecutionEventListener.class)\n\tpublic static class TransactionManagerTestConfiguration {\n\n\t\t@Bean\n\t\tpublic PlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t\t@Bean\n\t\tpublic BatchProperties batchProperties() {\n\t\t\treturn new BatchProperties();\n\t\t}\n\n\t\t@Bean\n\t\tpublic JobRegistry jobRegistry() {\n\t\t\treturn new MapJobRegistry();\n\t\t}\n\n\t\t@Bean\n\t\tDataSourceScriptDatabaseInitializer batchDataSourceInitializer(DataSource dataSource) {\n\t\t\tDatabaseInitializationSettings settings = new DatabaseInitializationSettings();\n\t\t\tsettings.setSchemaLocations(Arrays.asList(\"classpath:org/springframework/batch/core/schema-h2.sql\"));\n\t\t\treturn new DataSourceScriptDatabaseInitializer(dataSource, settings);\n\t\t}\n\n\t}\n\n\t@EnableBatchProcessing\n\t@EnableJdbcJobRepository\n\t@ImportAutoConfiguration({ PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class,\n\t\t\tTaskBatchAutoConfiguration.class, TaskJobLauncherAutoConfiguration.class, SingleTaskConfiguration.class,\n\t\t\tSimpleTaskAutoConfiguration.class, SimpleTaskAutoConfiguration.class })\n\t@Import({ EmbeddedDataSourceConfiguration.class, TransactionManagerTestConfiguration.class })\n\t@EnableTask\n\tpublic static class JobWithFailureConfiguration {\n\n\t\t@Autowired\n\t\tprivate JobRepository jobRepository;\n\n\t\t@Autowired\n\t\tprivate PlatformTransactionManager transactionManager;\n\n\t\t@Bean\n\t\tpublic Job jobFail() {\n\t\t\treturn new JobBuilder(\"jobA\", this.jobRepository)\n\t\t\t\t.start(new StepBuilder(\"step1\", this.jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\t\tthrow new IllegalStateException(\"WHOOPS\");\n\t\t\t\t}, transactionManager).build())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic Job jobFun() {\n\t\t\treturn new JobBuilder(\"jobSucceed\", this.jobRepository)\n\t\t\t\t.start(new StepBuilder(\"step1Succeed\", this.jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}, transactionManager).build())\n\t\t\t\t.build();\n\t\t}\n\n\t}\n\n\t@EnableTask\n\tpublic static class JobWithFailureAnnotatedConfiguration extends JobWithFailureConfiguration {\n\n\t}\n\n\t@Import(JobWithFailureConfiguration.class)\n\t@Configuration\n\t@EnableTask\n\tpublic static class JobWithFailureTaskExecutorConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/PrefixTests.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport java.util.Set;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.cloud.task.batch.configuration.TaskBatchTest;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.AssertionsForClassTypes.assertThat;\n\n/**\n * @author Glenn Renfro\n */\npublic class PrefixTests {\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Disabled(\"Unable to find TaskRepository\")\n\t@Test\n\tpublic void testPrefix() {\n\t\tthis.applicationContext = SpringApplication.run(JobConfiguration.class, \"--spring.cloud.task.tablePrefix=FOO_\");\n\n\t\tTaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);\n\n\t\tSet<Long> jobIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(1);\n\t\tassertThat(jobIds.size()).isEqualTo(1);\n\t\tassertThat(jobIds.contains(1L));\n\t}\n\n\t@AutoConfiguration\n\t@TaskBatchTest\n\t@EnableTask\n\tpublic static class JobConfiguration {\n\n\t\t@Bean\n\t\tpublic Job job(JobRepository jobRepository, PlatformTransactionManager transactionManager) {\n\t\t\treturn new JobBuilder(\"job\", jobRepository)\n\t\t\t\t.start(new StepBuilder(\"step1\", jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}, transactionManager).build())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic DataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().addScript(\"classpath:schema-h2.sql\")\n\t\t\t\t.setType(EmbeddedDatabaseType.H2)\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/PrimaryKeyTests.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport java.util.Set;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.cloud.task.batch.configuration.TaskBatchTest;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Henning Pöttker\n */\nclass PrimaryKeyTests {\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\t@AfterEach\n\tvoid tearDown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Disabled(\"Unable to find TaskRepository\")\n\t@Test\n\tvoid testSchemaWithPrimaryKeys() {\n\t\tthis.applicationContext = SpringApplication.run(JobConfiguration.class);\n\n\t\tTaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);\n\n\t\tSet<Long> jobIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(1);\n\t\tassertThat(jobIds).containsExactly(1L);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@TaskBatchTest\n\t@EnableTask\n\tstatic class JobConfiguration {\n\n\t\t@Bean\n\t\tJob job(JobRepository jobRepository, PlatformTransactionManager transactionManager) {\n\t\t\treturn new JobBuilder(\"job\", jobRepository)\n\t\t\t\t.start(new StepBuilder(\"step1\", jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}, transactionManager).build())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tDataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().addScript(\"classpath:schema-with-primary-keys-h2.sql\")\n\t\t\t\t.setType(EmbeddedDatabaseType.H2)\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/TaskBatchExecutionListenerTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Disabled;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.SimpleJob;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.scope.context.ChunkContext;\nimport org.springframework.batch.core.step.StepContribution;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.core.step.tasklet.Tasklet;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.batch.autoconfigure.BatchAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration;\nimport org.springframework.cloud.task.batch.configuration.TaskBatchExecutionListenerBeanPostProcessor;\nimport org.springframework.cloud.task.batch.configuration.TaskBatchTest;\nimport org.springframework.cloud.task.configuration.DefaultTaskConfigurer;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.configuration.SingleTaskConfiguration;\nimport org.springframework.cloud.task.configuration.TaskConfigurer;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatThrownBy;\n\n/**\n * @author Michael Minella\n * @author Glenn Renfro\n */\n@Disabled(\"Tests can not fined TaskRepository\")\npublic class TaskBatchExecutionListenerTests {\n\n\tprivate static final String[] ARGS = new String[] {};\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testAutobuiltDataSource() {\n\t\tthis.applicationContext = SpringApplication.run(JobConfiguration.class, ARGS);\n\t\tvalidateContext();\n\t}\n\n\t@Test\n\tpublic void testNoAutoConfigurationEnabled() {\n\t\tthis.applicationContext = SpringApplication.run(JobConfiguration.class,\n\t\t\t\t\"--spring.cloud.task.batch.listener.enabled=false\");\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(() -> {\n\t\t\tvalidateContext();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testNoAutoConfigurationEnable() {\n\t\tthis.applicationContext = SpringApplication.run(JobConfiguration.class,\n\t\t\t\t\"--spring.cloud.task.batch.listener.enable=false\");\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(() -> {\n\t\t\tvalidateContext();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testNoAutoConfigurationBothDisabled() {\n\t\tthis.applicationContext = SpringApplication.run(JobConfiguration.class,\n\t\t\t\t\"--spring.cloud.task.batch.listener.enable=false --spring.cloud.task.batch.listener.enabled=false\");\n\t\tassertThatExceptionOfType(AssertionError.class).isThrownBy(() -> {\n\t\t\tvalidateContext();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testAutoConfigurationEnable() {\n\t\tthis.applicationContext = SpringApplication.run(JobConfiguration.class,\n\t\t\t\t\"--spring.cloud.task.batch.listener.enable=true\");\n\t\tvalidateContext();\n\t}\n\n\t@Test\n\tpublic void testAutoConfigurationEnabled() {\n\t\tthis.applicationContext = SpringApplication.run(JobConfiguration.class,\n\t\t\t\t\"--spring.cloud.task.batch.listener.enabled=true\");\n\t\tvalidateContext();\n\t}\n\n\t@Test\n\tpublic void testFactoryBean() {\n\t\tthis.applicationContext = SpringApplication.run(JobFactoryBeanConfiguration.class, ARGS);\n\t\tvalidateContext();\n\t}\n\n\tprivate void validateContext() {\n\t\tTaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);\n\n\t\tPage<TaskExecution> page = taskExplorer.findTaskExecutionsByName(\"application\", PageRequest.of(0, 1));\n\n\t\tSet<Long> jobExecutionIds = taskExplorer\n\t\t\t.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId());\n\n\t\tassertThat(jobExecutionIds.size()).isEqualTo(1);\n\t\tassertThat(taskExplorer.getTaskExecution(jobExecutionIds.iterator().next()).getExecutionId()).isEqualTo(1);\n\n\t}\n\n\t@Test\n\tpublic void testNoListenerIfTaskNotEnabled() {\n\t\tthis.applicationContext = SpringApplication.run(TaskNotEnabledConfiguration.class, ARGS);\n\t\tassertThat(applicationContext.getBean(Job.class)).isNotNull();\n\t\tassertThatThrownBy(() -> applicationContext.getBean(TaskBatchExecutionListenerBeanPostProcessor.class))\n\t\t\t.isInstanceOf(NoSuchBeanDefinitionException.class);\n\t\tassertThatThrownBy(() -> applicationContext.getBean(TaskBatchExecutionListener.class))\n\t\t\t.isInstanceOf(NoSuchBeanDefinitionException.class);\n\t}\n\n\t@Test\n\tpublic void testMultipleDataSources() {\n\t\tthis.applicationContext = SpringApplication.run(JobConfigurationMultipleDataSources.class, ARGS);\n\n\t\tTaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);\n\n\t\tPage<TaskExecution> page = taskExplorer.findTaskExecutionsByName(\"application\", PageRequest.of(0, 1));\n\n\t\tSet<Long> jobExecutionIds = taskExplorer\n\t\t\t.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId());\n\n\t\tassertThat(jobExecutionIds.size()).isEqualTo(1);\n\t\tassertThat(taskExplorer.getTaskExecution(jobExecutionIds.iterator().next()).getExecutionId()).isEqualTo(1);\n\t}\n\n\t@Test\n\tpublic void testAutobuiltDataSourceNoJob() {\n\t\tthis.applicationContext = SpringApplication.run(NoJobConfiguration.class, ARGS);\n\n\t\tTaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);\n\n\t\tPage<TaskExecution> page = taskExplorer.findTaskExecutionsByName(\"application\", PageRequest.of(0, 1));\n\n\t\tSet<Long> jobExecutionIds = taskExplorer\n\t\t\t.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId());\n\n\t\tassertThat(jobExecutionIds.size()).isEqualTo(0);\n\t}\n\n\t@Test\n\tpublic void testMapBased() {\n\t\tthis.applicationContext = SpringApplication.run(JobConfiguration.class, ARGS);\n\n\t\tTaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);\n\n\t\tPage<TaskExecution> page = taskExplorer.findTaskExecutionsByName(\"application\", PageRequest.of(0, 1));\n\n\t\tSet<Long> jobExecutionIds = taskExplorer\n\t\t\t.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId());\n\n\t\tassertThat(jobExecutionIds.size()).isEqualTo(1);\n\t\tassertThat((long) taskExplorer.getTaskExecutionIdByJobExecutionId(jobExecutionIds.iterator().next()))\n\t\t\t.isEqualTo(1);\n\t}\n\n\t@Test\n\tpublic void testMultipleJobs() {\n\t\tthis.applicationContext = SpringApplication.run(MultipleJobConfiguration.class, \"--spring.batch.job.name=job1\");\n\n\t\tTaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);\n\n\t\tPage<TaskExecution> page = taskExplorer.findTaskExecutionsByName(\"application\", PageRequest.of(0, 1));\n\n\t\tSet<Long> jobExecutionIds = taskExplorer\n\t\t\t.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId());\n\n\t\tassertThat(jobExecutionIds.size()).isEqualTo(1);\n\t\tIterator<Long> jobExecutionIdsIterator = jobExecutionIds.iterator();\n\t\tassertThat((long) taskExplorer.getTaskExecutionIdByJobExecutionId(jobExecutionIdsIterator.next())).isEqualTo(1);\n\n\t}\n\n\t@Test\n\tpublic void testBatchExecutionListenerBeanPostProcessorWithJobNames() {\n\t\tList<String> jobNames = new ArrayList<>(3);\n\t\tjobNames.add(\"job1\");\n\t\tjobNames.add(\"job2\");\n\t\tjobNames.add(\"TESTOBJECT\");\n\n\t\tTaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = beanPostProcessor(jobNames);\n\n\t\tSimpleJob testObject = new SimpleJob();\n\t\tSimpleJob bean = (SimpleJob) beanPostProcessor.postProcessBeforeInitialization(testObject, \"TESTOBJECT\");\n\t\tassertThat(bean).isEqualTo(testObject);\n\t}\n\n\t@Test\n\tpublic void testBatchExecutionListenerBeanPostProcessorWithEmptyJobNames() {\n\t\tTaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = beanPostProcessor(Collections.emptyList());\n\n\t\tSimpleJob testObject = new SimpleJob();\n\t\tSimpleJob bean = (SimpleJob) beanPostProcessor.postProcessBeforeInitialization(testObject, \"TESTOBJECT\");\n\t\tassertThat(bean).isEqualTo(testObject);\n\t}\n\n\t@Test\n\tpublic void testBatchExecutionListenerBeanPostProcessorNullJobNames() {\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tbeanPostProcessor(null);\n\t\t});\n\t}\n\n\tprivate TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor(List<String> jobNames) {\n\t\tthis.applicationContext = SpringApplication.run(new Class[] { JobConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\tBatchAutoConfiguration.class, TaskBatchAutoConfiguration.class, SimpleTaskAutoConfiguration.class,\n\t\t\t\tSingleTaskConfiguration.class }, ARGS);\n\n\t\tTaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = this.applicationContext\n\t\t\t.getBean(TaskBatchExecutionListenerBeanPostProcessor.class);\n\n\t\tbeanPostProcessor.setJobNames(jobNames);\n\t\treturn beanPostProcessor;\n\t}\n\n\t@EnableBatchProcessing\n\t@TaskBatchTest\n\t@Import(EmbeddedDataSourceConfiguration.class)\n\t@EnableTask\n\tpublic static class NoJobConfiguration {\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t}\n\n\t@TaskBatchTest\n\t@Import(EmbeddedDataSourceConfiguration.class)\n\t@EnableTask\n\tpublic static class JobConfiguration {\n\n\t\t@Bean\n\t\tpublic Job job(JobRepository jobRepository, PlatformTransactionManager transactionManager) {\n\t\t\treturn new JobBuilder(\"job\", jobRepository)\n\t\t\t\t.start(new StepBuilder(\"step1\", jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}, transactionManager).build())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t}\n\n\t@EnableBatchProcessing\n\t@TaskBatchTest\n\t@Import(EmbeddedDataSourceConfiguration.class)\n\tpublic static class TaskNotEnabledConfiguration {\n\n\t\t@Bean\n\t\tpublic Job job(JobRepository jobRepository, PlatformTransactionManager transactionManager) {\n\t\t\treturn new JobBuilder(\"job\", jobRepository)\n\t\t\t\t.start(new StepBuilder(\"step1\", jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}, transactionManager).build())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t}\n\n\t@TaskBatchTest\n\t@EnableTask\n\t@Import(EmbeddedDataSourceConfiguration.class)\n\tpublic static class JobFactoryBeanConfiguration {\n\n\t\t@Bean\n\t\tpublic FactoryBean<Job> job(JobRepository jobRepository, PlatformTransactionManager transactionManager) {\n\t\t\treturn new FactoryBean<Job>() {\n\t\t\t\t@Override\n\t\t\t\tpublic Job getObject() {\n\t\t\t\t\treturn new JobBuilder(\"job\", jobRepository)\n\t\t\t\t\t\t.start(new StepBuilder(\"step1\", jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t\t\t}, transactionManager).build())\n\t\t\t\t\t\t.build();\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic Class<?> getObjectType() {\n\t\t\t\t\treturn Job.class;\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic boolean isSingleton() {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t}\n\n\t@TaskBatchTest\n\t@EnableTask\n\t@Import(EmbeddedDataSourceConfiguration.class)\n\tpublic static class JobConfigurationMultipleDataSources {\n\n\t\t@Bean\n\t\tpublic Job job(JobRepository jobRepository) {\n\t\t\treturn new JobBuilder(\"job\", jobRepository)\n\t\t\t\t.start(new StepBuilder(\"step1\", jobRepository).tasklet(new Tasklet() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext)\n\t\t\t\t\t\t\tthrows Exception {\n\t\t\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t\t}\n\t\t\t\t}, new ResourcelessTransactionManager()).build())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\t@Primary\n\t\tpublic DataSource myDataSource() {\n\t\t\tEmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)\n\t\t\t\t.setName(\"myDataSource\");\n\t\t\treturn builder.build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic DataSource incorrectDataSource() {\n\t\t\tEmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)\n\t\t\t\t.setName(\"incorrectDataSource\");\n\t\t\treturn builder.build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic TaskConfigurer taskConfigurer() {\n\t\t\treturn new DefaultTaskConfigurer(myDataSource());\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t}\n\n\t@TaskBatchTest\n\t@EnableTask\n\t@Import(EmbeddedDataSourceConfiguration.class)\n\tpublic static class MultipleJobConfiguration {\n\n\t\t@Bean\n\t\tpublic Job job1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {\n\t\t\treturn new JobBuilder(\"job1\", jobRepository)\n\t\t\t\t.start(new StepBuilder(\"job1step1\", jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\tSystem.out.println(\"Executed job1\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}, transactionManager).build())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic Job job2(JobRepository jobRepository, PlatformTransactionManager transactionManager) {\n\t\t\treturn new JobBuilder(\"job2\", jobRepository)\n\t\t\t\t.start(new StepBuilder(\"job2step1\", jobRepository).tasklet((contribution, chunkContext) -> {\n\t\t\t\t\tSystem.out.println(\"Executed job2\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}, transactionManager).build())\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tPlatformTransactionManager transactionManager() {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-batch/src/test/resources/META-INF/spring/org.springframework.cloud.task.batch.configuration.TaskBatchTest.imports",
    "content": "org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration\norg.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration\norg.springframework.boot.batch.autoconfigure.BatchAutoConfiguration\norg.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration\norg.springframework.cloud.task.configuration.SingleTaskConfiguration\n"
  },
  {
    "path": "spring-cloud-task-batch/src/test/resources/schema-h2.sql",
    "content": "\nCREATE TABLE FOO_EXECUTION  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,\n\tSTART_TIME TIMESTAMP DEFAULT NULL ,\n\tEND_TIME TIMESTAMP DEFAULT NULL ,\n\tTASK_NAME  VARCHAR(100) ,\n\tEXIT_CODE INTEGER ,\n\tEXIT_MESSAGE VARCHAR(2500) ,\n\tERROR_MESSAGE VARCHAR(2500) ,\n\tLAST_UPDATED TIMESTAMP,\n\tEXTERNAL_EXECUTION_ID VARCHAR(255),\n\tPARENT_EXECUTION_ID BIGINT\n);\n\nCREATE TABLE FOO_EXECUTION_PARAMS  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL ,\n\tTASK_PARAM VARCHAR(2500) ,\n\tconstraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)\n\treferences FOO_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE TABLE FOO_TASK_BATCH (\n  TASK_EXECUTION_ID BIGINT NOT NULL ,\n  JOB_EXECUTION_ID BIGINT NOT NULL ,\n\tconstraint TASK_EXEC_BATCH_FK foreign key (TASK_EXECUTION_ID)\n\treferences FOO_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE SEQUENCE FOO_SEQ ;\n\nCREATE TABLE FOO_LOCK  (\n\tLOCK_KEY CHAR(36) NOT NULL,\n\tREGION VARCHAR(100) NOT NULL,\n\tCLIENT_ID CHAR(36),\n\tCREATED_DATE TIMESTAMP NOT NULL,\n\tconstraint LOCK_PK primary key (LOCK_KEY, REGION)\n);\n"
  },
  {
    "path": "spring-cloud-task-batch/src/test/resources/schema-with-primary-keys-h2.sql",
    "content": "\nCREATE TABLE TASK_EXECUTION  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,\n\tSTART_TIME TIMESTAMP DEFAULT NULL ,\n\tEND_TIME TIMESTAMP DEFAULT NULL ,\n\tTASK_NAME  VARCHAR(100) ,\n\tEXIT_CODE INTEGER ,\n\tEXIT_MESSAGE VARCHAR(2500) ,\n\tERROR_MESSAGE VARCHAR(2500) ,\n\tLAST_UPDATED TIMESTAMP,\n\tEXTERNAL_EXECUTION_ID VARCHAR(255),\n\tPARENT_EXECUTION_ID BIGINT\n);\n\nCREATE TABLE TASK_EXECUTION_PARAMS  (\n\tID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n\tTASK_EXECUTION_ID BIGINT NOT NULL ,\n\tTASK_PARAM VARCHAR(2500) ,\n\tconstraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE TABLE TASK_TASK_BATCH (\n  ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,\n  TASK_EXECUTION_ID BIGINT NOT NULL ,\n  JOB_EXECUTION_ID BIGINT NOT NULL ,\n\tconstraint TASK_EXEC_BATCH_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE SEQUENCE TASK_SEQ ;\n\nCREATE TABLE TASK_LOCK  (\n\tLOCK_KEY CHAR(36) NOT NULL,\n\tREGION VARCHAR(100) NOT NULL,\n\tCLIENT_ID CHAR(36),\n\tCREATED_DATE TIMESTAMP NOT NULL,\n\tconstraint LOCK_PK primary key (LOCK_KEY, REGION)\n);\n"
  },
  {
    "path": "spring-cloud-task-core/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<artifactId>spring-cloud-task-parent</artifactId>\n\t\t<version>5.0.2-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>spring-cloud-task-core</artifactId>\n\t<packaging>jar</packaging>\n\t<name>Spring Cloud Task Core</name>\n\t<description>Spring Cloud Task</description>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-autoconfigure</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-sql</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-jdbc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>ch.qos.logback</groupId>\n\t\t\t<artifactId>logback-classic</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-jdbc</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-micrometer-metrics</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-micrometer-tracing</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-zipkin</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.tomcat</groupId>\n\t\t\t<artifactId>tomcat-jdbc</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.batch</groupId>\n\t\t\t<artifactId>spring-batch-infrastructure</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.data</groupId>\n\t\t\t<artifactId>spring-data-commons</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.integration</groupId>\n\t\t\t<artifactId>spring-integration-core</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.integration</groupId>\n\t\t\t<artifactId>spring-integration-jdbc</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>jakarta.platform</groupId>\n\t\t\t<artifactId>jakarta.jakartaee-api</artifactId>\n\t\t\t<version>${jakarta-ee-api.version}</version>\n\t\t\t<optional>true</optional>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework</groupId>\n\t\t\t<artifactId>spring-orm</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.hibernate.validator</groupId>\n\t\t\t<artifactId>hibernate-validator</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter-api</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-autoconfigure-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-actuator-autoconfigure</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.micrometer</groupId>\n\t\t\t<artifactId>micrometer-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.micrometer</groupId>\n\t\t\t<artifactId>micrometer-observation</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>io.micrometer</groupId>\n\t\t\t<artifactId>micrometer-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.micrometer</groupId>\n\t\t\t<artifactId>micrometer-observation-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter-params</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.junit.jupiter</groupId>\n\t\t\t<artifactId>junit-jupiter-engine</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.micrometer</groupId>\n\t\t\t<artifactId>micrometer-tracing-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.micrometer</groupId>\n\t\t\t<artifactId>micrometer-tracing-bridge-brave</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.zipkin.brave</groupId>\n\t\t\t<artifactId>brave-tests</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-micrometer-tracing-brave</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.zipkin.reporter2</groupId>\n\t\t\t<artifactId>zipkin-reporter-brave</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.zipkin.reporter2</groupId>\n\t\t\t<artifactId>zipkin-sender-urlconnection</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers-junit-jupiter</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers-mariadb</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mariadb.jdbc</groupId>\n\t\t\t<artifactId>mariadb-java-client</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-micrometer-tracing-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n</project>\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/DefaultTaskConfigurer.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport javax.sql.DataSource;\n\nimport jakarta.persistence.EntityManager;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.TaskNameResolver;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao;\nimport org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;\nimport org.springframework.cloud.task.repository.support.SimpleTaskExplorer;\nimport org.springframework.cloud.task.repository.support.SimpleTaskNameResolver;\nimport org.springframework.cloud.task.repository.support.SimpleTaskRepository;\nimport org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.jdbc.support.JdbcTransactionManager;\nimport org.springframework.orm.jpa.JpaTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * Default implementation of the TaskConfigurer interface. If no {@link TaskConfigurer}\n * implementation is present, then this configuration will be used. The following defaults\n * will be used:\n * <ul>\n * <li>{@link SimpleTaskRepository} is the default {@link TaskRepository} returned. If a\n * data source is present then a data will be stored in the database\n * {@link JdbcTaskExecutionDao} else it will be stored in a map\n * {@link MapTaskExecutionDao}.\n * </ul>\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @author Mahmoud Ben Hassine\n */\npublic class DefaultTaskConfigurer implements TaskConfigurer {\n\n\tprivate static final Log logger = LogFactory.getLog(DefaultTaskConfigurer.class);\n\n\tprivate TaskProperties taskProperties;\n\n\tprivate TaskRepository taskRepository;\n\n\tprivate TaskExplorer taskExplorer;\n\n\tprivate PlatformTransactionManager transactionManager;\n\n\tprivate DataSource dataSource;\n\n\tprivate ApplicationContext context;\n\n\tpublic DefaultTaskConfigurer() {\n\t\tthis(TaskProperties.DEFAULT_TABLE_PREFIX);\n\t}\n\n\t/**\n\t * Initializes the DefaultTaskConfigurer and retrieves table prefix from\n\t * {@link TaskProperties}.\n\t */\n\tpublic DefaultTaskConfigurer(TaskProperties taskProperties) {\n\t\tthis(null, null, null, taskProperties);\n\t}\n\n\t/**\n\t * Initializes the DefaultTaskConfigurer and sets the default table prefix to\n\t * {@link TaskProperties#DEFAULT_TABLE_PREFIX}.\n\t * @param dataSource references the {@link DataSource} to be used as the Task\n\t * repository. If none is provided, a Map will be used (not recommended for production\n\t * use).\n\t */\n\tpublic DefaultTaskConfigurer(DataSource dataSource) {\n\t\tthis(dataSource, TaskProperties.DEFAULT_TABLE_PREFIX, null);\n\t}\n\n\t/**\n\t * Initializes the DefaultTaskConfigurer and retrieves table prefix from *\n\t * {@link TaskProperties}.\n\t * @param dataSource references the {@link DataSource} to be used as the Task\n\t * repository. If none is provided, a Map will be used (not recommended for production\n\t * use).\n\t * @param taskProperties the task properties used to obtain tablePrefix if not set by\n\t * tablePrefix field.\n\t */\n\tpublic DefaultTaskConfigurer(DataSource dataSource, TaskProperties taskProperties) {\n\t\tthis(dataSource, null, null, taskProperties);\n\t}\n\n\t/**\n\t * Initializes the DefaultTaskConfigurer.\n\t * @param tablePrefix the prefix to apply to the task table names used by task\n\t * infrastructure.\n\t */\n\tpublic DefaultTaskConfigurer(String tablePrefix) {\n\t\tthis(null, tablePrefix, null);\n\t}\n\n\t/**\n\t * Initializes the DefaultTaskConfigurer.\n\t * @param tablePrefix the prefix to apply to the task table names used by task\n\t * infrastructure.\n\t * @param taskProperties the task properties used to obtain tablePrefix if not set by\n\t * tablePrefix field.\n\t */\n\tpublic DefaultTaskConfigurer(String tablePrefix, TaskProperties taskProperties) {\n\t\tthis(null, tablePrefix, null, taskProperties);\n\t}\n\n\t/**\n\t * Initializes the DefaultTaskConfigurer.\n\t * @param dataSource references the {@link DataSource} to be used as the Task\n\t * repository. If none is provided, a Map will be used (not recommended for production\n\t * use).\n\t * @param tablePrefix the prefix to apply to the task table names used by task\n\t * infrastructure.\n\t * @param context the context to be used.\n\t */\n\tpublic DefaultTaskConfigurer(DataSource dataSource, String tablePrefix, ApplicationContext context) {\n\t\tthis(dataSource, tablePrefix, context, null);\n\t}\n\n\t/**\n\t * Initializes the DefaultTaskConfigurer.\n\t * @param dataSource references the {@link DataSource} to be used as the Task\n\t * repository. If none is provided, a Map will be used (not recommended for production\n\t * use).\n\t * @param tablePrefix the prefix to apply to the task table names used by task\n\t * infrastructure.\n\t * @param context the context to be used.\n\t * @param taskProperties the task properties used to obtain tablePrefix if not set by\n\t * tablePrefix field.\n\t */\n\tpublic DefaultTaskConfigurer(DataSource dataSource, String tablePrefix, ApplicationContext context,\n\t\t\tTaskProperties taskProperties) {\n\t\tthis.dataSource = dataSource;\n\t\tthis.context = context;\n\n\t\tTaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean;\n\t\tthis.taskProperties = taskProperties;\n\n\t\tif (tablePrefix == null) {\n\t\t\ttablePrefix = (taskProperties != null && !taskProperties.getTablePrefix().isEmpty())\n\t\t\t\t\t? taskProperties.getTablePrefix() : TaskProperties.DEFAULT_TABLE_PREFIX;\n\t\t}\n\n\t\tif (this.dataSource != null) {\n\t\t\ttaskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(this.dataSource, tablePrefix);\n\t\t}\n\t\telse {\n\t\t\ttaskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean();\n\t\t}\n\n\t\tthis.taskRepository = new SimpleTaskRepository(taskExecutionDaoFactoryBean);\n\t\tthis.taskExplorer = new SimpleTaskExplorer(taskExecutionDaoFactoryBean);\n\t}\n\n\t@Override\n\tpublic TaskRepository getTaskRepository() {\n\t\treturn this.taskRepository;\n\t}\n\n\t@Override\n\tpublic TaskExplorer getTaskExplorer() {\n\t\treturn this.taskExplorer;\n\t}\n\n\t@Override\n\tpublic DataSource getTaskDataSource() {\n\t\treturn this.dataSource;\n\t}\n\n\t@Override\n\tpublic TaskNameResolver getTaskNameResolver() {\n\t\treturn new SimpleTaskNameResolver();\n\t}\n\n\t@Override\n\tpublic PlatformTransactionManager getTransactionManager() {\n\t\tif (this.transactionManager == null) {\n\t\t\tif (isDataSourceAvailable()) {\n\t\t\t\ttry {\n\t\t\t\t\tClass.forName(\"jakarta.persistence.EntityManager\");\n\t\t\t\t\tif (this.context != null && this.context.getBeanNamesForType(EntityManager.class).length > 0) {\n\t\t\t\t\t\tlogger.debug(\"EntityManager was found, using JpaTransactionManager\");\n\t\t\t\t\t\tthis.transactionManager = new JpaTransactionManager();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (ClassNotFoundException ignore) {\n\t\t\t\t\tlogger.debug(\"No EntityManager was found, using DataSourceTransactionManager\");\n\t\t\t\t}\n\t\t\t\tfinally {\n\t\t\t\t\tif (this.transactionManager == null) {\n\t\t\t\t\t\tthis.transactionManager = new JdbcTransactionManager(this.dataSource);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.debug(\"No DataSource was found, using ResourcelessTransactionManager\");\n\t\t\t\tthis.transactionManager = new ResourcelessTransactionManager();\n\t\t\t}\n\t\t}\n\t\treturn this.transactionManager;\n\t}\n\n\tprivate boolean isDataSourceAvailable() {\n\t\treturn this.dataSource != null;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/EnableTask.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.context.annotation.Import;\n\n/**\n * <p>\n * Enables the {@link org.springframework.cloud.task.listener.TaskLifecycleListener} so\n * that the features of Spring Cloud Task will be applied.\n *\n * <pre class=\"code\">\n * &#064;Configuration\n * &#064;EnableTask\n * public class AppConfig {\n *\n * \t&#064;Bean\n * \tpublic MyCommandLineRunner myCommandLineRunner() {\n * \t\treturn new MyCommandLineRunner()\n *    }\n * }\n * </pre>\n *\n * Note that only one of your configuration classes needs to have the\n * <code>&#064;EnableTask</code> annotation. Once you have an\n * <code>&#064;EnableTask</code> class in your configuration the task will have the Spring\n * Cloud Task features available.\n *\n * @author Glenn Renfro\n *\n */\n@Target(ElementType.TYPE)\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Inherited\n@Import(TaskLifecycleConfiguration.class)\npublic @interface EnableTask {\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/NoTransactionManagerProperty.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.autoconfigure.condition.NoneNestedConditions;\n\n/**\n * A condition that verifies that the spring.cloud.task.transaction-manager property is\n * not being used.\n *\n * @author Glenn Renfro\n * @since 3.0\n */\nclass NoTransactionManagerProperty extends NoneNestedConditions {\n\n\tNoTransactionManagerProperty() {\n\t\tsuper(ConfigurationPhase.REGISTER_BEAN);\n\t}\n\n\t@ConditionalOnProperty(prefix = \"spring.cloud.task\", name = \"transaction-manager\")\n\tstatic class OnProperty {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskAutoConfiguration.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport javax.sql.DataSource;\n\nimport jakarta.annotation.PostConstruct;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.aop.scope.ScopedProxyUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.TaskNameResolver;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.repository.support.SimpleTaskRepository;\nimport org.springframework.cloud.task.repository.support.TaskRepositoryInitializer;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Conditional;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.annotation.EnableTransactionManagement;\nimport org.springframework.util.CollectionUtils;\n\n/**\n * Base {@code Configuration} class providing common structure for enabling and using\n * Spring Task. Customization is available by implementing the {@link TaskConfigurer}\n * interface.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @author Mahmoud Ben Hassine\n */\n@AutoConfiguration\n@EnableTransactionManagement\n@EnableConfigurationProperties({ TaskProperties.class })\n// @checkstyle:off\n@ConditionalOnProperty(prefix = \"spring.cloud.task.autoconfiguration\", name = \"enabled\", havingValue = \"true\",\n\t\tmatchIfMissing = true)\n// @checkstyle:on\n@Import(DatabaseInitializationDependencyConfigurer.class)\npublic class SimpleTaskAutoConfiguration {\n\n\tprotected static final Log logger = LogFactory.getLog(SimpleTaskAutoConfiguration.class);\n\n\t@Autowired(required = false)\n\tprivate Collection<DataSource> dataSources;\n\n\t@Autowired\n\tprivate ConfigurableApplicationContext context;\n\n\t@Autowired\n\tprivate TaskProperties taskProperties;\n\n\tprivate boolean initialized = false;\n\n\tprivate TaskRepository taskRepository;\n\n\tprivate PlatformTransactionManager platformTransactionManager;\n\n\tprivate TaskExplorer taskExplorer;\n\n\tprivate TaskNameResolver taskNameResolver;\n\n\t@Bean\n\tpublic SimpleTaskRepository taskRepository() {\n\t\treturn (SimpleTaskRepository) this.taskRepository;\n\t}\n\n\t@Conditional(NoTransactionManagerProperty.class)\n\t@Bean\n\tpublic PlatformTransactionManager springCloudTaskTransactionManager() {\n\t\treturn this.platformTransactionManager;\n\t}\n\n\t@Bean\n\tpublic TaskExplorer taskExplorer() {\n\t\treturn this.taskExplorer;\n\t}\n\n\t@Bean\n\tpublic TaskNameResolver taskNameResolver() {\n\t\treturn taskNameResolver;\n\t}\n\n\t@Bean\n\tpublic TaskRepositoryInitializer taskRepositoryInitializer() {\n\t\tTaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer(this.taskProperties);\n\t\tDataSource initializerDataSource = getDefaultConfigurer().getTaskDataSource();\n\t\tif (initializerDataSource != null) {\n\t\t\ttaskRepositoryInitializer.setDataSource(initializerDataSource);\n\t\t}\n\n\t\treturn taskRepositoryInitializer;\n\t}\n\n\t@Bean\n\t@Profile(\"cloud\")\n\tTaskObservationCloudKeyValues taskObservationCloudKeyValues() {\n\t\treturn new TaskObservationCloudKeyValues();\n\t}\n\n\t/**\n\t * Determines the {@link TaskConfigurer} to use.\n\t */\n\t@PostConstruct\n\tprotected void initialize() {\n\t\tif (this.initialized) {\n\t\t\treturn;\n\t\t}\n\n\t\tTaskConfigurer taskConfigurer = getDefaultConfigurer();\n\n\t\tlogger.debug(String.format(\"Using %s TaskConfigurer\", taskConfigurer.getClass().getName()));\n\n\t\tthis.taskRepository = taskConfigurer.getTaskRepository();\n\t\tthis.platformTransactionManager = taskConfigurer.getTransactionManager();\n\t\tthis.taskExplorer = taskConfigurer.getTaskExplorer();\n\t\tthis.taskNameResolver = taskConfigurer.getTaskNameResolver();\n\t\tthis.initialized = true;\n\t}\n\n\tprivate TaskConfigurer getDefaultConfigurer() {\n\t\tverifyEnvironment();\n\n\t\tint configurers = this.context.getBeanNamesForType(TaskConfigurer.class).length;\n\n\t\tif (configurers < 1) {\n\t\t\tTaskConfigurer taskConfigurer;\n\t\t\tif (!CollectionUtils.isEmpty(this.dataSources) && this.dataSources.size() == 1) {\n\t\t\t\ttaskConfigurer = new DefaultTaskConfigurer(this.dataSources.iterator().next(),\n\t\t\t\t\t\tthis.taskProperties.getTablePrefix(), this.context);\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttaskConfigurer = new DefaultTaskConfigurer(this.taskProperties.getTablePrefix());\n\t\t\t}\n\t\t\tthis.context.getBeanFactory().registerSingleton(\"taskConfigurer\", taskConfigurer);\n\t\t\treturn taskConfigurer;\n\t\t}\n\t\telse {\n\t\t\tif (configurers == 1) {\n\t\t\t\treturn this.context.getBean(TaskConfigurer.class);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new IllegalStateException(\"Expected one TaskConfigurer but found \" + configurers);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void verifyEnvironment() {\n\t\tint configurers = this.context.getBeanNamesForType(TaskConfigurer.class).length;\n\t\t// retrieve the count of dataSources (without instantiating them) excluding\n\t\t// DataSource proxy beans\n\t\tlong dataSources = Arrays.stream(this.context.getBeanNamesForType(DataSource.class))\n\t\t\t.filter((name -> !ScopedProxyUtils.isScopedTarget(name)))\n\t\t\t.count();\n\n\t\tif (configurers == 0 && dataSources > 1) {\n\t\t\tthrow new IllegalStateException(\"To use the default TaskConfigurer the context must contain no more than\"\n\t\t\t\t\t+ \" one DataSource, found \" + dataSources);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SingleInstanceTaskListener.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport java.time.Duration;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.cloud.task.listener.TaskExecutionException;\nimport org.springframework.cloud.task.listener.annotation.AfterTask;\nimport org.springframework.cloud.task.listener.annotation.BeforeTask;\nimport org.springframework.cloud.task.listener.annotation.FailedTask;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskNameResolver;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.integration.jdbc.lock.DefaultLockRepository;\nimport org.springframework.integration.jdbc.lock.JdbcLockRegistry;\nimport org.springframework.integration.leader.DefaultCandidate;\nimport org.springframework.integration.leader.event.OnFailedToAcquireMutexEvent;\nimport org.springframework.integration.leader.event.OnGrantedEvent;\nimport org.springframework.integration.support.leader.LockRegistryLeaderInitiator;\nimport org.springframework.integration.support.locks.LockRegistry;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * When spring.cloud.task.single-instance-enabled is set to true this listener will create\n * a lock for the task based on the spring.cloud.task.name. If a lock already exists this\n * Listener will throw a TaskExecutionException. If this listener is added manually, then\n * it should be added as the first listener in the chain.\n *\n * @author Glenn Renfro\n * @author Mahmoud Ben Hassine\n * @since 2.0.0\n */\npublic class SingleInstanceTaskListener implements ApplicationListener<ApplicationEvent> {\n\n\tprivate static final Log logger = LogFactory.getLog(SingleInstanceTaskListener.class);\n\n\tprivate LockRegistry lockRegistry;\n\n\tprivate LockRegistryLeaderInitiator lockRegistryLeaderInitiator;\n\n\tprivate TaskNameResolver taskNameResolver;\n\n\tprivate ApplicationEventPublisher applicationEventPublisher;\n\n\tprivate boolean lockReady;\n\n\tprivate boolean lockFailed;\n\n\tprivate DataSource dataSource;\n\n\tprivate TaskProperties taskProperties;\n\n\tprivate ApplicationContext applicationContext;\n\n\tprivate PlatformTransactionManager platformTransactionManager;\n\n\tpublic SingleInstanceTaskListener(LockRegistry lockRegistry, TaskNameResolver taskNameResolver,\n\t\t\tTaskProperties taskProperties, ApplicationEventPublisher applicationEventPublisher,\n\t\t\tApplicationContext applicationContext) {\n\t\tthis.lockRegistry = lockRegistry;\n\t\tthis.taskNameResolver = taskNameResolver;\n\t\tthis.taskProperties = taskProperties;\n\t\tthis.lockRegistryLeaderInitiator = new LockRegistryLeaderInitiator(this.lockRegistry);\n\t\tthis.applicationEventPublisher = applicationEventPublisher;\n\t\tthis.applicationContext = applicationContext;\n\t}\n\n\tpublic SingleInstanceTaskListener(DataSource dataSource, TaskNameResolver taskNameResolver,\n\t\t\tTaskProperties taskProperties, ApplicationEventPublisher applicationEventPublisher,\n\t\t\tApplicationContext applicationContext) {\n\t\tthis.taskNameResolver = taskNameResolver;\n\t\tthis.applicationEventPublisher = applicationEventPublisher;\n\t\tthis.dataSource = dataSource;\n\t\tthis.taskProperties = taskProperties;\n\t\tthis.applicationContext = applicationContext;\n\t\tthis.platformTransactionManager = this.applicationContext.getBean(\"springCloudTaskTransactionManager\",\n\t\t\t\tPlatformTransactionManager.class);\n\t}\n\n\t@BeforeTask\n\tpublic void lockTask(TaskExecution taskExecution) {\n\t\tif (this.lockRegistry == null) {\n\t\t\tthis.lockRegistry = getDefaultLockRegistry(taskExecution.getExecutionId());\n\t\t}\n\t\tthis.lockRegistryLeaderInitiator = new LockRegistryLeaderInitiator(this.lockRegistry, new DefaultCandidate(\n\t\t\t\tString.valueOf(taskExecution.getExecutionId()), this.taskNameResolver.getTaskName()));\n\t\tthis.lockRegistryLeaderInitiator.setApplicationEventPublisher(this.applicationEventPublisher);\n\t\tthis.lockRegistryLeaderInitiator.setPublishFailedEvents(true);\n\t\tthis.lockRegistryLeaderInitiator.start();\n\t\twhile (!this.lockReady) {\n\t\t\ttry {\n\t\t\t\tThread.sleep(this.taskProperties.getSingleInstanceLockCheckInterval());\n\t\t\t}\n\t\t\tcatch (InterruptedException ex) {\n\t\t\t\tlogger.warn(\"Thread Sleep Failed\", ex);\n\t\t\t}\n\t\t\tif (this.lockFailed) {\n\t\t\t\tString errorMessage = String.format(\"Task with name \\\"%s\\\" is already running.\",\n\t\t\t\t\t\tthis.taskNameResolver.getTaskName());\n\t\t\t\ttry {\n\t\t\t\t\tthis.lockRegistryLeaderInitiator.destroy();\n\t\t\t\t}\n\t\t\t\tcatch (Exception exception) {\n\t\t\t\t\tthrow new TaskExecutionException(\"Failed to destroy lock.\", exception);\n\t\t\t\t}\n\t\t\t\tthrow new TaskExecutionException(errorMessage);\n\t\t\t}\n\t\t}\n\t}\n\n\t@AfterTask\n\tpublic void unlockTaskOnEnd(TaskExecution taskExecution) throws Exception {\n\t\tthis.lockRegistryLeaderInitiator.destroy();\n\t}\n\n\t@FailedTask\n\tpublic void unlockTaskOnError(TaskExecution taskExecution, Throwable throwable) throws Exception {\n\t\tthis.lockRegistryLeaderInitiator.destroy();\n\t}\n\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEvent applicationEvent) {\n\t\tif (applicationEvent instanceof OnGrantedEvent) {\n\t\t\tthis.lockReady = true;\n\t\t}\n\t\telse if (applicationEvent instanceof OnFailedToAcquireMutexEvent) {\n\t\t\tthis.lockFailed = true;\n\t\t}\n\t}\n\n\tprivate LockRegistry getDefaultLockRegistry(long executionId) {\n\t\tDefaultLockRepository lockRepository = new DefaultLockRepository(this.dataSource, String.valueOf(executionId));\n\t\tlockRepository.setPrefix(this.taskProperties.getTablePrefix());\n\t\tlockRepository.setApplicationContext(this.applicationContext);\n\t\tlockRepository.afterPropertiesSet();\n\t\tlockRepository.setTransactionManager(this.platformTransactionManager);\n\t\tlockRepository.afterSingletonsInstantiated();\n\t\treturn new JdbcLockRegistry(lockRepository, Duration.ofSeconds(this.taskProperties.getSingleInstanceLockTtl()));\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SingleTaskConfiguration.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.cloud.task.repository.TaskNameResolver;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.Ordered;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.integration.support.locks.PassThruLockRegistry;\n\n/**\n * Autoconfiguration of {@link SingleInstanceTaskListener}.\n *\n * @author Glenn Renfro\n * @since 2.0.0\n */\n\n@Order(Ordered.HIGHEST_PRECEDENCE)\n@AutoConfiguration\n@ConditionalOnProperty(prefix = \"spring.cloud.task\", name = \"single-instance-enabled\", havingValue = \"true\")\npublic class SingleTaskConfiguration {\n\n\t@Autowired\n\tprivate TaskProperties taskProperties;\n\n\t@Autowired\n\tprivate ApplicationEventPublisher applicationEventPublisher;\n\n\t@Autowired\n\tprivate TaskConfigurer taskConfigurer;\n\n\t@Bean\n\tpublic SingleInstanceTaskListener taskListener(TaskNameResolver resolver, ApplicationContext applicationContext) {\n\t\tif (this.taskConfigurer.getTaskDataSource() == null) {\n\t\t\treturn new SingleInstanceTaskListener(new PassThruLockRegistry(), resolver, this.taskProperties,\n\t\t\t\t\tthis.applicationEventPublisher, applicationContext);\n\t\t}\n\n\t\treturn new SingleInstanceTaskListener(this.taskConfigurer.getTaskDataSource(), resolver, this.taskProperties,\n\t\t\t\tthis.applicationEventPublisher, applicationContext);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskConfigurer.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.TaskNameResolver;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * Provides a strategy interface for providing configuration customization to the task\n * system. Users should not directly use getter methods from a <code>TaskConfigurer</code>\n * directly unless they are using it to supply the implementations for Spring Beans.\n *\n * @author Glenn Renfro\n */\npublic interface TaskConfigurer {\n\n\t/**\n\t * Create a {@link TaskRepository} for the Task.\n\t * @return A TaskRepository\n\t */\n\tTaskRepository getTaskRepository();\n\n\t/**\n\t * Create a {@link PlatformTransactionManager} for use with the\n\t * <code>TaskRepository</code>.\n\t * @return A <code>PlatformTransactionManager</code>\n\t */\n\tPlatformTransactionManager getTransactionManager();\n\n\t/**\n\t * Create a {@link TaskExplorer} for the task.\n\t * @return a <code>TaskExplorer</code>\n\t */\n\tTaskExplorer getTaskExplorer();\n\n\t/**\n\t * Retrieves the {@link DataSource} that will be used for task operations. If a\n\t * DataSource is not being used for the implemented TaskConfigurer this method will\n\t * return null.\n\t * @return {@link DataSource} that will be used for task operations.\n\t */\n\tDataSource getTaskDataSource();\n\n\t/**\n\t * Create a {@link TaskNameResolver} for use with the task application.\n\t * @return A <code>TaskNameResolver</code>\n\t */\n\tTaskNameResolver getTaskNameResolver();\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskLifecycleConfiguration.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport io.micrometer.observation.ObservationRegistry;\nimport jakarta.annotation.PostConstruct;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.ObjectProvider;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.cloud.task.listener.TaskLifecycleListener;\nimport org.springframework.cloud.task.listener.TaskListenerExecutorObjectFactory;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.TaskNameResolver;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Configuration for a {@link TaskLifecycleListener}.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @since 2.1\n */\n@Configuration(proxyBeanMethods = false)\npublic class TaskLifecycleConfiguration {\n\n\tprotected static final Log logger = LogFactory.getLog(TaskLifecycleConfiguration.class);\n\n\tprivate TaskProperties taskProperties;\n\n\tprivate ConfigurableApplicationContext context;\n\n\tprivate ApplicationArguments applicationArguments;\n\n\tprivate TaskRepository taskRepository;\n\n\tprivate TaskExplorer taskExplorer;\n\n\tprivate TaskNameResolver taskNameResolver;\n\n\tprivate TaskLifecycleListener taskLifecycleListener;\n\n\tprivate boolean initialized = false;\n\n\tprivate ObservationRegistry observationRegistry;\n\n\tprivate TaskObservationCloudKeyValues taskObservationCloudKeyValues;\n\n\t@Autowired\n\tpublic TaskLifecycleConfiguration(TaskProperties taskProperties, ConfigurableApplicationContext context,\n\t\t\tTaskRepository taskRepository, TaskExplorer taskExplorer, TaskNameResolver taskNameResolver,\n\t\t\tObjectProvider<ApplicationArguments> applicationArguments,\n\t\t\t@Autowired(required = false) ObservationRegistry observationRegistry,\n\t\t\t@Autowired(required = false) TaskObservationCloudKeyValues taskObservationCloudKeyValues) {\n\n\t\tthis.taskProperties = taskProperties;\n\t\tthis.context = context;\n\t\tthis.taskRepository = taskRepository;\n\t\tthis.taskExplorer = taskExplorer;\n\t\tthis.taskNameResolver = taskNameResolver;\n\t\tthis.applicationArguments = applicationArguments.getIfAvailable();\n\t\tthis.observationRegistry = observationRegistry == null ? ObservationRegistry.NOOP : observationRegistry;\n\t\tthis.taskObservationCloudKeyValues = taskObservationCloudKeyValues;\n\n\t}\n\n\t@Bean\n\tpublic TaskLifecycleListener taskLifecycleListener() {\n\t\treturn this.taskLifecycleListener;\n\t}\n\n\t/**\n\t * Initializes the {@link TaskLifecycleListener} for the task app.\n\t */\n\t@PostConstruct\n\tprotected void initialize() {\n\t\tif (!this.initialized) {\n\t\t\tthis.taskLifecycleListener = new TaskLifecycleListener(this.taskRepository, this.taskNameResolver,\n\t\t\t\t\tthis.applicationArguments, this.taskExplorer, this.taskProperties,\n\t\t\t\t\tnew TaskListenerExecutorObjectFactory(this.context), this.observationRegistry,\n\t\t\t\t\ttaskObservationCloudKeyValues);\n\n\t\t\tthis.initialized = true;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskObservationCloudKeyValues.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport org.springframework.beans.factory.annotation.Value;\n\n/**\n * Provides values for the {@link io.micrometer.common.KeyValues} for the task\n * {@link io.micrometer.observation.Observation} when the cloud profile is active.\n *\n * @author Glenn Renfro\n * @since 3.0\n */\npublic class TaskObservationCloudKeyValues {\n\n\t@Value(\"${vcap.application.org_name:default}\")\n\tprivate String organizationName;\n\n\t@Value(\"${vcap.application.space_id:unknown}\")\n\tprivate String spaceId;\n\n\t@Value(\"${vcap.application.space_name:unknown}\")\n\tprivate String spaceName;\n\n\t@Value(\"${vcap.application.application_name:unknown}\")\n\tprivate String applicationName;\n\n\t@Value(\"${vcap.application.application_id:unknown}\")\n\tprivate String applicationId;\n\n\t@Value(\"${vcap.application.application_version:unknown}\")\n\tprivate String applicationVersion;\n\n\t@Value(\"${vcap.application.instance_index:0}\")\n\tprivate String instanceIndex;\n\n\tpublic String getOrganizationName() {\n\t\treturn organizationName;\n\t}\n\n\tpublic void setOrganizationName(String organizationName) {\n\t\tthis.organizationName = organizationName;\n\t}\n\n\tpublic String getSpaceId() {\n\t\treturn spaceId;\n\t}\n\n\tpublic void setSpaceId(String spaceId) {\n\t\tthis.spaceId = spaceId;\n\t}\n\n\tpublic String getSpaceName() {\n\t\treturn spaceName;\n\t}\n\n\tpublic void setSpaceName(String spaceName) {\n\t\tthis.spaceName = spaceName;\n\t}\n\n\tpublic String getApplicationName() {\n\t\treturn applicationName;\n\t}\n\n\tpublic void setApplicationName(String applicationName) {\n\t\tthis.applicationName = applicationName;\n\t}\n\n\tpublic String getApplicationId() {\n\t\treturn applicationId;\n\t}\n\n\tpublic void setApplicationId(String applicationId) {\n\t\tthis.applicationId = applicationId;\n\t}\n\n\tpublic String getApplicationVersion() {\n\t\treturn applicationVersion;\n\t}\n\n\tpublic void setApplicationVersion(String applicationVersion) {\n\t\tthis.applicationVersion = applicationVersion;\n\t}\n\n\tpublic String getInstanceIndex() {\n\t\treturn instanceIndex;\n\t}\n\n\tpublic void setInstanceIndex(String instanceIndex) {\n\t\tthis.instanceIndex = instanceIndex;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskProperties.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\n\n/**\n * Properties available to configure the task.\n *\n * @author Glenn Renfro\n * @author David Turanski\n */\n\n@ConfigurationProperties(prefix = \"spring.cloud.task\")\npublic class TaskProperties {\n\n\t/**\n\t * Default table prefix for Spring Cloud Task tables.\n\t */\n\tpublic static final String DEFAULT_TABLE_PREFIX = \"TASK_\";\n\n\tprivate static final int DEFAULT_CHECK_INTERVAL = 500;\n\n\tprivate static final Log logger = LogFactory.getLog(TaskProperties.class);\n\n\t/**\n\t * An id that can be associated with a task.\n\t */\n\tprivate String externalExecutionId;\n\n\t/**\n\t * An id that will be used by the task when updating the task execution.\n\t */\n\tprivate Long executionid;\n\n\t/**\n\t * The id of the parent task execution id that launched this task execution. Defaults\n\t * to null if task execution had no parent.\n\t */\n\tprivate Long parentExecutionId;\n\n\t/**\n\t * The prefix to append to the table names created by Spring Cloud Task.\n\t */\n\tprivate String tablePrefix = DEFAULT_TABLE_PREFIX;\n\n\t/**\n\t * When set to true the context is closed at the end of the task. Else the context\n\t * remains open.\n\t */\n\tprivate Boolean closecontextEnabled = false;\n\n\t/**\n\t * When set to true it will check to see if a task execution with the same task name\n\t * is already running. If a task is still running then it will throw a\n\t * {@link org.springframework.cloud.task.listener.TaskExecutionException}. When task\n\t * execution ends the lock is released.\n\t */\n\tprivate boolean singleInstanceEnabled = false;\n\n\t/**\n\t * Declares the maximum amount of time (in millis) that a task execution can hold a\n\t * lock to prevent another task from executing with a specific task name when the\n\t * single-instance-enabled is set to true. Default time is: Integer.MAX_VALUE.\n\t */\n\tprivate int singleInstanceLockTtl = Integer.MAX_VALUE;\n\n\t/**\n\t * Declares the time (in millis) that a task execution will wait between checks.\n\t * Default time is: 500 millis.\n\t */\n\tprivate int singleInstanceLockCheckInterval = DEFAULT_CHECK_INTERVAL;\n\n\t/**\n\t * If set to true then tables are initialized. If set to false tables are not\n\t * initialized. Defaults to null. The requirement for it to be defaulted to null is so\n\t * that we can support the <code>spring.cloud.task.initialize.enable</code> until it\n\t * is removed.\n\t */\n\tprivate Boolean initializeEnabled;\n\n\tpublic String getExternalExecutionId() {\n\t\treturn this.externalExecutionId;\n\t}\n\n\tpublic void setExternalExecutionId(String externalExecutionId) {\n\t\tthis.externalExecutionId = externalExecutionId;\n\t}\n\n\tpublic Long getExecutionid() {\n\t\treturn this.executionid;\n\t}\n\n\tpublic void setExecutionid(Long executionid) {\n\t\tthis.executionid = executionid;\n\t}\n\n\tpublic Boolean getClosecontextEnabled() {\n\t\treturn this.closecontextEnabled;\n\t}\n\n\tpublic void setClosecontextEnabled(Boolean closecontextEnabled) {\n\t\tthis.closecontextEnabled = closecontextEnabled;\n\t}\n\n\tpublic String getTablePrefix() {\n\t\treturn this.tablePrefix;\n\t}\n\n\tpublic void setTablePrefix(String tablePrefix) {\n\t\tthis.tablePrefix = tablePrefix;\n\t}\n\n\tpublic Long getParentExecutionId() {\n\t\treturn this.parentExecutionId;\n\t}\n\n\tpublic void setParentExecutionId(Long parentExecutionId) {\n\t\tthis.parentExecutionId = parentExecutionId;\n\t}\n\n\tpublic boolean getSingleInstanceEnabled() {\n\t\treturn this.singleInstanceEnabled;\n\t}\n\n\tpublic void setSingleInstanceEnabled(boolean singleInstanceEnabled) {\n\t\tthis.singleInstanceEnabled = singleInstanceEnabled;\n\t}\n\n\tpublic int getSingleInstanceLockTtl() {\n\t\treturn this.singleInstanceLockTtl;\n\t}\n\n\tpublic void setSingleInstanceLockTtl(int singleInstanceLockTtl) {\n\t\tthis.singleInstanceLockTtl = singleInstanceLockTtl;\n\t}\n\n\tpublic int getSingleInstanceLockCheckInterval() {\n\t\treturn this.singleInstanceLockCheckInterval;\n\t}\n\n\tpublic void setSingleInstanceLockCheckInterval(int singleInstanceLockCheckInterval) {\n\t\tthis.singleInstanceLockCheckInterval = singleInstanceLockCheckInterval;\n\t}\n\n\tpublic Boolean isInitializeEnabled() {\n\t\treturn initializeEnabled;\n\t}\n\n\tpublic void setInitializeEnabled(Boolean initializeEnabled) {\n\t\tthis.initializeEnabled = initializeEnabled;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskRepositoryDatabaseInitializerDetector.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport java.util.Set;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDatabaseInitializerDetector;\nimport org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector;\nimport org.springframework.cloud.task.repository.support.TaskRepositoryInitializer;\nimport org.springframework.core.Ordered;\n\n/**\n * {@link DatabaseInitializerDetector} for {@link TaskRepositoryInitializer}.\n *\n * @author Henning Pöttker\n */\nclass TaskRepositoryDatabaseInitializerDetector extends AbstractBeansOfTypeDatabaseInitializerDetector {\n\n\tprivate static final int PRECEDENCE = Ordered.LOWEST_PRECEDENCE - 99;\n\n\t@Override\n\tprotected Set<Class<?>> getDatabaseInitializerBeanTypes() {\n\t\treturn Set.of(TaskRepositoryInitializer.class);\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn PRECEDENCE;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskRepositoryDependsOnDatabaseInitializationDetector.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport java.util.Set;\n\nimport org.springframework.boot.sql.init.dependency.AbstractBeansOfTypeDependsOnDatabaseInitializationDetector;\nimport org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector;\nimport org.springframework.cloud.task.repository.TaskRepository;\n\n/**\n * {@link DependsOnDatabaseInitializationDetector} for {@link TaskRepository}.\n *\n * @author Henning Pöttker\n */\nclass TaskRepositoryDependsOnDatabaseInitializationDetector\n\t\textends AbstractBeansOfTypeDependsOnDatabaseInitializationDetector {\n\n\t@Override\n\tprotected Set<Class<?>> getDependsOnDatabaseInitializationBeanTypes() {\n\t\treturn Set.of(TaskRepository.class);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskRuntimeHints.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport java.sql.Statement;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.aot.hint.TypeReference;\nimport org.springframework.util.ClassUtils;\n\n/**\n * Native Hints for Spring Cloud Task.\n *\n * @author Glenn Renfro\n * @author Mahmoud Ben Hassine\n * @since 3.0\n */\npublic class TaskRuntimeHints implements RuntimeHintsRegistrar {\n\n\t@Override\n\tpublic void registerHints(RuntimeHints hints, ClassLoader classLoader) {\n\t\thints.reflection().registerType(TypeReference.of(\"java.sql.DatabaseMetaData\"), hint -> {\n\t\t});\n\t\thints.resources().registerPattern(\"org/springframework/cloud/task/schema-db2.sql\");\n\t\thints.resources().registerPattern(\"org/springframework/cloud/task/schema-h2.sql\");\n\t\thints.resources().registerPattern(\"org/springframework/cloud/task/schema-mysql.sql\");\n\t\thints.resources().registerPattern(\"org/springframework/cloud/task/schema-mariadb.sql\");\n\t\thints.resources().registerPattern(\"org/springframework/cloud/task/schema-oracle.sql\");\n\t\thints.resources().registerPattern(\"org/springframework/cloud/task/schema-postgresql.sql\");\n\t\thints.resources().registerPattern(\"org/springframework/cloud/task/schema-hsqldb.sql\");\n\t\thints.resources().registerPattern(\"org/springframework/cloud/task/schema-sqlserver.sql\");\n\n\t\thints.reflection()\n\t\t\t.registerType(TypeReference.of(\"org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer\"),\n\t\t\t\t\thint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,\n\t\t\t\t\t\t\tMemberCategory.INVOKE_DECLARED_METHODS));\n\t\thints.reflection()\n\t\t\t.registerType(TypeReference.of(\"org.springframework.cloud.task.repository.TaskExecution\"), hint -> hint\n\t\t\t\t.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS));\n\n\t\tif (!ClassUtils.isPresent(\"com.zaxxer.hikari.HikariDataSource\", classLoader)) {\n\t\t\treturn;\n\t\t}\n\t\thints.reflection().registerType(Statement[].class, hint -> {\n\t\t});\n\t\thints.reflection()\n\t\t\t.registerType(TypeReference.of(\"com.zaxxer.hikari.util.ConcurrentBag$IConcurrentBagEntry[]\"), hint -> {\n\t\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/observation/DefaultTaskObservationConvention.java",
    "content": "/*\n * Copyright 2013-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration.observation;\n\nimport io.micrometer.common.KeyValues;\nimport io.micrometer.observation.ObservationConvention;\n\n/**\n * {@link ObservationConvention} for Spring Cloud Task.\n *\n * @author Marcin Grzejszczak\n * @since 3.0.0\n */\npublic class DefaultTaskObservationConvention implements TaskObservationConvention {\n\n\t@Override\n\tpublic KeyValues getLowCardinalityKeyValues(TaskObservationContext context) {\n\t\treturn KeyValues.of(TaskDocumentedObservation.TaskRunnerTags.BEAN_NAME.withValue(context.getBeanName()));\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn \"spring.cloud.task.runner\";\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/observation/ObservationApplicationRunner.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration.observation;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\n\n/**\n * Observed representation of a {@link ApplicationRunner}.\n *\n * @author Marcin Grzejszczak\n */\nclass ObservationApplicationRunner implements ApplicationRunner {\n\n\tprivate static final DefaultTaskObservationConvention INSTANCE = new DefaultTaskObservationConvention();\n\n\tprivate final BeanFactory beanFactory;\n\n\tprivate final ApplicationRunner delegate;\n\n\tprivate final String beanName;\n\n\tprivate ObservationRegistry registry;\n\n\tprivate TaskObservationConvention taskObservationConvention;\n\n\tObservationApplicationRunner(BeanFactory beanFactory, ApplicationRunner delegate, String beanName) {\n\t\tthis.beanFactory = beanFactory;\n\t\tthis.delegate = delegate;\n\t\tthis.beanName = beanName;\n\t}\n\n\t@Override\n\tpublic void run(ApplicationArguments args) throws Exception {\n\t\tTaskObservationContext context = new TaskObservationContext(this.beanName);\n\t\tObservation observation = TaskDocumentedObservation.TASK_RUNNER_OBSERVATION\n\t\t\t.observation(this.taskObservationConvention, INSTANCE, context, registry())\n\t\t\t.contextualName(this.beanName);\n\n\t\ttry (Observation.Scope scope = observation.start().openScope()) {\n\t\t\tthis.delegate.run(args);\n\t\t}\n\t\tcatch (Exception error) {\n\t\t\tobservation.error(error);\n\t\t\tthrow error;\n\t\t}\n\t\tfinally {\n\t\t\tobservation.stop();\n\t\t}\n\t}\n\n\tprivate ObservationRegistry registry() {\n\t\tif (this.registry == null) {\n\t\t\tthis.registry = this.beanFactory.getBean(ObservationRegistry.class);\n\t\t}\n\t\treturn this.registry;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/observation/ObservationApplicationRunnerBeanPostProcessor.java",
    "content": "/*\n * Copyright 2013-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration.observation;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.ApplicationRunner;\n\n/**\n * Registers beans related to task scheduling.\n *\n * @author Marcin Grzejszczak\n */\nclass ObservationApplicationRunnerBeanPostProcessor implements BeanPostProcessor {\n\n\tprivate final BeanFactory beanFactory;\n\n\tObservationApplicationRunnerBeanPostProcessor(BeanFactory beanFactory) {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (bean instanceof ApplicationRunner applicationRunner && !(bean instanceof ObservationApplicationRunner)) {\n\t\t\treturn new ObservationApplicationRunner(this.beanFactory, applicationRunner, beanName);\n\t\t}\n\t\treturn bean;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/observation/ObservationCommandLineRunner.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration.observation;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.boot.CommandLineRunner;\n\n/**\n * Observed representation of a {@link CommandLineRunner}.\n *\n * @author Marcin Grzejszczak\n */\nclass ObservationCommandLineRunner implements CommandLineRunner {\n\n\tprivate static final DefaultTaskObservationConvention INSTANCE = new DefaultTaskObservationConvention();\n\n\tprivate final BeanFactory beanFactory;\n\n\tprivate final CommandLineRunner delegate;\n\n\tprivate final String beanName;\n\n\tprivate ObservationRegistry registry;\n\n\tprivate TaskObservationConvention taskObservationConvention;\n\n\tObservationCommandLineRunner(BeanFactory beanFactory, CommandLineRunner delegate, String beanName) {\n\t\tthis.beanFactory = beanFactory;\n\t\tthis.delegate = delegate;\n\t\tthis.beanName = beanName;\n\t}\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\tTaskObservationContext context = new TaskObservationContext(this.beanName);\n\t\tObservation observation = TaskDocumentedObservation.TASK_RUNNER_OBSERVATION\n\t\t\t.observation(this.taskObservationConvention, INSTANCE, context, registry())\n\t\t\t.contextualName(this.beanName);\n\t\ttry (Observation.Scope scope = observation.start().openScope()) {\n\t\t\tthis.delegate.run(args);\n\t\t}\n\t\tcatch (Exception error) {\n\t\t\tobservation.error(error);\n\t\t\tthrow error;\n\t\t}\n\t\tfinally {\n\t\t\tobservation.stop();\n\t\t}\n\t}\n\n\tprivate ObservationRegistry registry() {\n\t\tif (this.registry == null) {\n\t\t\tthis.registry = this.beanFactory.getBean(ObservationRegistry.class);\n\t\t}\n\t\treturn this.registry;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/observation/ObservationCommandLineRunnerBeanPostProcessor.java",
    "content": "/*\n * Copyright 2013-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration.observation;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.boot.CommandLineRunner;\n\n/**\n * Registers beans related to task scheduling.\n *\n * @author Marcin Grzejszczak\n */\nclass ObservationCommandLineRunnerBeanPostProcessor implements BeanPostProcessor {\n\n\tprivate final BeanFactory beanFactory;\n\n\tObservationCommandLineRunnerBeanPostProcessor(BeanFactory beanFactory) {\n\t\tthis.beanFactory = beanFactory;\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\tif (bean instanceof CommandLineRunner commandLineRunner && !(bean instanceof ObservationCommandLineRunner)) {\n\t\t\treturn new ObservationCommandLineRunner(this.beanFactory, commandLineRunner, beanName);\n\t\t}\n\t\treturn bean;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/observation/ObservationTaskAutoConfiguration.java",
    "content": "/*\n * Copyright 2013-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration.observation;\n\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.BeanFactory;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration\n * Auto-configuration} that registers instrumentation for Spring Cloud Task.\n *\n * @author Marcin Grzejszczak\n * @since 3.0.0\n */\n@AutoConfiguration\n@ConditionalOnClass(ObservationRegistry.class)\n@ConditionalOnProperty(value = \"spring.cloud.task.observation.enabled\", matchIfMissing = true)\n@ConditionalOnBean(ObservationRegistry.class)\npublic class ObservationTaskAutoConfiguration {\n\n\t@Bean\n\tstatic ObservationCommandLineRunnerBeanPostProcessor observedCommandLineRunnerBeanPostProcessor(\n\t\t\tBeanFactory beanFactory) {\n\t\treturn new ObservationCommandLineRunnerBeanPostProcessor(beanFactory);\n\t}\n\n\t@Bean\n\tstatic ObservationApplicationRunnerBeanPostProcessor observedApplicationRunnerBeanPostProcessor(\n\t\t\tBeanFactory beanFactory) {\n\t\treturn new ObservationApplicationRunnerBeanPostProcessor(beanFactory);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/observation/TaskDocumentedObservation.java",
    "content": "/*\n * Copyright 2013-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration.observation;\n\nimport io.micrometer.common.docs.KeyName;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationConvention;\nimport io.micrometer.observation.docs.ObservationDocumentation;\n\nenum TaskDocumentedObservation implements ObservationDocumentation {\n\n\t/**\n\t * Observation created when a task runner is executed.\n\t */\n\tTASK_RUNNER_OBSERVATION {\n\n\t\t@Override\n\t\tpublic Class<? extends ObservationConvention<? extends Observation.Context>> getDefaultConvention() {\n\t\t\treturn DefaultTaskObservationConvention.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic KeyName[] getLowCardinalityKeyNames() {\n\t\t\treturn TaskRunnerTags.values();\n\t\t}\n\n\t\t@Override\n\t\tpublic String getPrefix() {\n\t\t\treturn \"spring.cloud.task\";\n\t\t}\n\t};\n\n\t/**\n\t * Key names for Spring Cloud Task Command / Application runners.\n\t */\n\tenum TaskRunnerTags implements KeyName {\n\n\t\t/**\n\t\t * Name of the bean that was executed by Spring Cloud Task.\n\t\t */\n\t\tBEAN_NAME {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.runner.bean-name\";\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/observation/TaskObservationContext.java",
    "content": "/*\n * Copyright 2013-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration.observation;\n\nimport java.util.function.Supplier;\n\nimport io.micrometer.observation.Observation;\n\n/**\n * {@link Observation.Context} for Spring Cloud Task.\n *\n * @author Marcin Grzejszczak\n * @since 3.0.0\n */\npublic class TaskObservationContext extends Observation.Context implements Supplier<TaskObservationContext> {\n\n\tprivate final String beanName;\n\n\tpublic TaskObservationContext(String beanName) {\n\t\tthis.beanName = beanName;\n\t}\n\n\tpublic String getBeanName() {\n\t\treturn beanName;\n\t}\n\n\t@Override\n\tpublic TaskObservationContext get() {\n\t\treturn this;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/observation/TaskObservationConvention.java",
    "content": "/*\n * Copyright 2013-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration.observation;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationConvention;\n\n/**\n * {@link ObservationConvention} for Spring Cloud Task.\n *\n * @author Marcin Grzejszczak\n * @since 3.0.0\n */\npublic interface TaskObservationConvention extends ObservationConvention<TaskObservationContext> {\n\n\t@Override\n\tdefault boolean supportsContext(Observation.Context context) {\n\t\treturn context instanceof TaskObservationContext;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/observation/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Observation support for Spring Cloud Task configuration.\n */\npackage org.springframework.cloud.task.configuration.observation;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/package-info.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Interfaces for configuring Spring Cloud Task and a default implementations.\n */\npackage org.springframework.cloud.task.configuration;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/DefaultTaskExecutionObservationConvention.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport io.micrometer.common.KeyValues;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\n\n/**\n * /** Default {@link TaskExecutionObservationConvention} implementation.\n *\n * @author Glenn Renfro\n * @since 3.0.0\n */\npublic class DefaultTaskExecutionObservationConvention implements TaskExecutionObservationConvention {\n\n\t@Override\n\tpublic KeyValues getLowCardinalityKeyValues(TaskExecutionObservationContext context) {\n\t\treturn getKeyValuesForTaskExecution(context);\n\t}\n\n\t@Override\n\tpublic KeyValues getHighCardinalityKeyValues(TaskExecutionObservationContext context) {\n\t\treturn KeyValues.empty();\n\t}\n\n\tprivate KeyValues getKeyValuesForTaskExecution(TaskExecutionObservationContext context) {\n\t\tTaskExecution execution = context.getTaskExecution();\n\t\treturn KeyValues.of(TaskExecutionObservation.TaskKeyValues.TASK_STATUS.asString(), context.getStatus(),\n\t\t\t\tTaskExecutionObservation.TaskKeyValues.TASK_EXIT_CODE.asString(),\n\t\t\t\tString.valueOf(execution.getExitCode()),\n\t\t\t\tTaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.asString(),\n\t\t\t\tString.valueOf(execution.getExecutionId()));\n\t}\n\n\t@Override\n\tpublic String getName() {\n\t\treturn \"spring.cloud.task\";\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskException.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\n/**\n * Base Exception for any Task issues.\n *\n * @author Glenn Renfro\n */\npublic class TaskException extends RuntimeException {\n\n\tpublic TaskException(String message, Throwable e) {\n\t\tsuper(message, e);\n\t}\n\n\tpublic TaskException(String message) {\n\t\tsuper(message);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskExecutionException.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\n/**\n * Is thrown when executing a task.\n *\n * @author Glenn Renfro.\n */\npublic class TaskExecutionException extends TaskException {\n\n\tpublic TaskExecutionException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic TaskExecutionException(String message, Throwable throwable) {\n\t\tsuper(message, throwable);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskExecutionListener.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskRepository;\n\n/**\n * The listener interface for receiving task execution events.\n *\n * @author Glenn Renfro\n */\npublic interface TaskExecutionListener {\n\n\t/**\n\t * Invoked after the {@link TaskExecution} has been stored in the\n\t * {@link TaskRepository}.\n\t * @param taskExecution instance containing the information about the current task.\n\t */\n\tdefault void onTaskStartup(TaskExecution taskExecution) {\n\t}\n\n\t/**\n\t * Invoked before the {@link TaskExecution} has been updated in the\n\t * {@link TaskRepository} upon task end.\n\t * @param taskExecution instance containing the information about the current task.\n\t */\n\tdefault void onTaskEnd(TaskExecution taskExecution) {\n\t}\n\n\t/**\n\t * Invoked if an uncaught exception occurs during a task execution. This invocation\n\t * will occur before the {@link TaskExecution} has been updated in the\n\t * {@link TaskRepository} and before the onTaskEnd is called.\n\t * @param taskExecution instance containing the information about the current task.\n\t * @param throwable the uncaught exception that was thrown during task execution.\n\t */\n\tdefault void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskExecutionListenerSupport.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\n/**\n * A no-op implementation of the {@link TaskExecutionListener} to allow for overriding\n * only the methods of interest.\n *\n * @author Michael Minella\n * @since 1.2\n *\n * {@link TaskExecutionListener}\n * @deprecated since 3.0 in favor of the default implementations of\n */\n@Deprecated\npublic class TaskExecutionListenerSupport implements TaskExecutionListener {\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskExecutionObservation.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport io.micrometer.common.docs.KeyName;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationConvention;\nimport io.micrometer.observation.docs.ObservationDocumentation;\n\n/**\n * Enumeration for task execution observations.\n *\n * @author Glenn Renfro\n * @since 3.0.0\n */\npublic enum TaskExecutionObservation implements ObservationDocumentation {\n\n\t/**\n\t * Metrics created around a task execution.\n\t */\n\tTASK_ACTIVE {\n\n\t\t@Override\n\t\tpublic Class<? extends ObservationConvention<? extends Observation.Context>> getDefaultConvention() {\n\t\t\treturn DefaultTaskExecutionObservationConvention.class;\n\t\t}\n\n\t\t@Override\n\t\tpublic KeyName[] getLowCardinalityKeyNames() {\n\t\t\treturn TaskKeyValues.values();\n\t\t}\n\n\t\tpublic String getPrefix() {\n\t\t\treturn \"spring.cloud.task\";\n\t\t}\n\t};\n\n\tpublic enum TaskKeyValues implements KeyName {\n\n\t\t/**\n\t\t * Task name measurement.\n\t\t */\n\t\tTASK_NAME {\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.name\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Task execution id.\n\t\t */\n\t\tTASK_EXECUTION_ID {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.execution.id\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Task parent execution id.\n\t\t */\n\t\tTASK_PARENT_EXECUTION_ID {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.parent.execution.id\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * External execution id for task.\n\t\t */\n\t\tTASK_EXTERNAL_EXECUTION_ID {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.external.execution.id\";\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * Task exit code.\n\t\t */\n\t\tTASK_EXIT_CODE {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.exit.code\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * task status. Can be either success or failure.\n\t\t */\n\t\tTASK_STATUS {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.status\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Organization Name for CF cloud.\n\t\t */\n\t\tTASK_CF_ORG_NAME {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.cf.org.name\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Space id for CF cloud.\n\t\t */\n\t\tTASK_CF_SPACE_ID {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.cf.space.id\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Space name for CF cloud.\n\t\t */\n\t\tTASK_CF_SPACE_NAME {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.cf.space.name\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * App name for CF cloud.\n\t\t */\n\t\tTASK_CF_APP_NAME {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.cf.app.name\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * App id for CF cloud.\n\t\t */\n\t\tTASK_CF_APP_ID {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.cf.app.id\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * App version for CF cloud.\n\t\t */\n\t\tTASK_CF_APP_VERSION {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.cf.app.version\";\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Instance index for CF cloud.\n\t\t */\n\t\tTASK_CF_INSTANCE_INDEX {\n\t\t\t@Override\n\t\t\tpublic String asString() {\n\t\t\t\treturn \"spring.cloud.task.cf.instance.index\";\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskExecutionObservationContext.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport java.util.function.Supplier;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationHandler;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\n\n/**\n * A mutable holder of the {@link TaskExecution} required by a {@link ObservationHandler}.\n *\n * @author Glenn Renfro\n * @since 3.0.0\n */\npublic class TaskExecutionObservationContext extends Observation.Context\n\t\timplements Supplier<TaskExecutionObservationContext> {\n\n\tprivate final TaskExecution taskExecution;\n\n\tprivate String exceptionMessage = \"none\";\n\n\tprivate String status = \"success\";\n\n\tpublic TaskExecutionObservationContext(TaskExecution taskExecution) {\n\t\tthis.taskExecution = taskExecution;\n\t}\n\n\tpublic TaskExecution getTaskExecution() {\n\t\treturn taskExecution;\n\t}\n\n\tpublic String getExceptionMessage() {\n\t\treturn exceptionMessage;\n\t}\n\n\tpublic void setExceptionMessage(String exceptionMessage) {\n\t\tthis.exceptionMessage = exceptionMessage;\n\t}\n\n\tpublic String getStatus() {\n\t\treturn status;\n\t}\n\n\tpublic void setStatus(String status) {\n\t\tthis.status = status;\n\t}\n\n\t@Override\n\tpublic TaskExecutionObservationContext get() {\n\t\treturn this;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskExecutionObservationConvention.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationConvention;\n\n/**\n * {@link ObservationConvention} for {@link TaskExecutionObservationContext}.\n *\n * @author Glenn Renfro\n * @since 3.0.0\n */\npublic interface TaskExecutionObservationConvention extends ObservationConvention<TaskExecutionObservationContext> {\n\n\t@Override\n\tdefault boolean supportsContext(Observation.Context context) {\n\t\treturn context instanceof TaskExecutionObservationContext;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.lang.reflect.InvocationTargetException;\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.micrometer.observation.ObservationConvention;\nimport io.micrometer.observation.ObservationRegistry;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.DisposableBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ExitCodeEvent;\nimport org.springframework.boot.ExitCodeGenerator;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.cloud.task.configuration.TaskObservationCloudKeyValues;\nimport org.springframework.cloud.task.configuration.TaskProperties;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.TaskNameResolver;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.context.ApplicationEvent;\nimport org.springframework.context.ApplicationListener;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.SmartLifecycle;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Monitors the lifecycle of a task. This listener will record both the start and end of a\n * task in the registered {@link TaskRepository}.\n *\n * The following events are used to identify the start and end of a task:\n *\n * <ul>\n * <li>{@link SmartLifecycle#start()} - Used to identify the start of a task. A task is\n * expected to contain a single application context.</li>\n * <li>{@link ApplicationReadyEvent} - Used to identify the successful end of a task.</li>\n * <li>{@link ApplicationFailedEvent} - Used to identify the failure of a task.</li>\n * <li>{@link SmartLifecycle#stop()} - Used to identify the end of a task, if the\n * {@link ApplicationReadyEvent} or {@link ApplicationFailedEvent} is not emitted. This\n * can occur if an error occurs while executing a BeforeTask.</li>\n * </ul>\n *\n * <b>Note:</b> By default, the context will close at the completion of the task unless\n * other non-daemon threads keep it running. Programatic closing of the context can be\n * configured via the property <code>spring.cloud.task.closecontext_enabled</code>\n * (defaults to false). If the <code>spring.cloud.task.closecontext_enabled</code> is set\n * to true, then the context will be closed upon task completion regardless if non-daemon\n * threads are still running. Also if the context did not start, the FailedTask and\n * TaskEnd may not have all the dependencies met.\n *\n * @author Michael Minella\n * @author Glenn Renfro\n */\npublic class TaskLifecycleListener\n\t\timplements ApplicationListener<ApplicationEvent>, SmartLifecycle, DisposableBean, Ordered {\n\n\tprivate static final Log logger = LogFactory.getLog(TaskLifecycleListener.class);\n\n\tprivate final TaskRepository taskRepository;\n\n\tprivate final TaskExplorer taskExplorer;\n\n\tprivate final TaskListenerExecutorObjectFactory taskListenerExecutorObjectFactory;\n\n\tprivate final TaskObservations taskObservations;\n\n\t@Autowired\n\tprivate ConfigurableApplicationContext context;\n\n\t@Autowired(required = false)\n\tprivate Collection<TaskExecutionListener> taskExecutionListenersFromContext;\n\n\t@Autowired(required = false)\n\tprivate ObservationConvention observationConvention;\n\n\tprivate List<TaskExecutionListener> taskExecutionListeners;\n\n\tprivate TaskExecution taskExecution;\n\n\tprivate TaskProperties taskProperties;\n\n\tprivate boolean started = false;\n\n\tprivate boolean finished = false;\n\n\tprivate boolean listenerFailed = false;\n\n\tprivate Throwable listenerException;\n\n\tprivate TaskNameResolver taskNameResolver;\n\n\tprivate ApplicationArguments applicationArguments;\n\n\tprivate Throwable applicationFailedException;\n\n\tprivate ExitCodeEvent exitCodeEvent;\n\n\t/**\n\t * @param taskRepository {@link TaskRepository} to record executions.\n\t * @param taskNameResolver {@link TaskNameResolver} used to determine task name for\n\t * task execution.\n\t * @param applicationArguments {@link ApplicationArguments} to be used for task\n\t * execution.\n\t * @param taskExplorer {@link TaskExplorer} to be used for task execution.\n\t * @param taskProperties {@link TaskProperties} to be used for the task execution.\n\t * @param taskListenerExecutorObjectFactory {@link TaskListenerExecutorObjectFactory}\n\t * to initialize TaskListenerExecutor for a task\n\t */\n\tpublic TaskLifecycleListener(TaskRepository taskRepository, TaskNameResolver taskNameResolver,\n\t\t\tApplicationArguments applicationArguments, TaskExplorer taskExplorer, TaskProperties taskProperties,\n\t\t\tTaskListenerExecutorObjectFactory taskListenerExecutorObjectFactory,\n\t\t\t@Autowired(required = false) ObservationRegistry observationRegistry,\n\t\t\tTaskObservationCloudKeyValues taskObservationCloudKeyValues) {\n\t\tAssert.notNull(taskRepository, \"A taskRepository is required\");\n\t\tAssert.notNull(taskNameResolver, \"A taskNameResolver is required\");\n\t\tAssert.notNull(taskExplorer, \"A taskExplorer is required\");\n\t\tAssert.notNull(taskProperties, \"TaskProperties is required\");\n\t\tAssert.notNull(taskListenerExecutorObjectFactory, \"A TaskListenerExecutorObjectFactory is required\");\n\n\t\tthis.taskRepository = taskRepository;\n\t\tthis.taskNameResolver = taskNameResolver;\n\t\tthis.applicationArguments = applicationArguments;\n\t\tthis.taskExplorer = taskExplorer;\n\t\tthis.taskProperties = taskProperties;\n\t\tthis.taskListenerExecutorObjectFactory = taskListenerExecutorObjectFactory;\n\t\tobservationRegistry = observationRegistry == null ? ObservationRegistry.NOOP : observationRegistry;\n\t\tthis.taskObservations = new TaskObservations(observationRegistry, taskObservationCloudKeyValues,\n\t\t\t\tobservationConvention);\n\t}\n\n\t/**\n\t * Utilizes {@link ApplicationEvent}s to determine the end and failure of a task.\n\t * Specifically:\n\t * <ul>\n\t * <li>{@link ApplicationReadyEvent} - Successful end of a task</li>\n\t * <li>{@link ApplicationFailedEvent} - Failure of a task</li>\n\t * </ul>\n\t * @param applicationEvent The application being listened for.\n\t */\n\t@Override\n\tpublic void onApplicationEvent(ApplicationEvent applicationEvent) {\n\t\tif (applicationEvent instanceof ApplicationFailedEvent) {\n\t\t\tthis.applicationFailedException = ((ApplicationFailedEvent) applicationEvent).getException();\n\t\t\tdoTaskEnd();\n\t\t}\n\t\telse if (applicationEvent instanceof ExitCodeEvent) {\n\t\t\tthis.exitCodeEvent = (ExitCodeEvent) applicationEvent;\n\t\t}\n\t\telse if (applicationEvent instanceof ApplicationReadyEvent) {\n\t\t\tdoTaskEnd();\n\t\t}\n\t}\n\n\tprivate String stackTraceToString(Throwable exception) {\n\t\tStringWriter writer = new StringWriter();\n\t\tPrintWriter printWriter = new PrintWriter(writer);\n\n\t\texception.printStackTrace(printWriter);\n\n\t\treturn writer.toString();\n\t}\n\n\tprivate void doTaskEnd() {\n\t\tif ((this.listenerFailed || this.started) && !this.finished) {\n\t\t\tthis.taskExecution.setEndTime(LocalDateTime.now());\n\n\t\t\tif (this.applicationFailedException != null) {\n\t\t\t\tthis.taskExecution.setErrorMessage(stackTraceToString(this.applicationFailedException));\n\t\t\t}\n\n\t\t\tthis.taskExecution.setExitCode(calcExitStatus());\n\t\t\tif (this.applicationFailedException != null) {\n\t\t\t\tsetExitMessage(invokeOnTaskError(this.taskExecution, this.applicationFailedException));\n\t\t\t}\n\n\t\t\tsetExitMessage(invokeOnTaskEnd(this.taskExecution));\n\t\t\tthis.taskRepository.completeTaskExecution(this.taskExecution.getExecutionId(),\n\t\t\t\t\tthis.taskExecution.getExitCode(), this.taskExecution.getEndTime(),\n\t\t\t\t\tthis.taskExecution.getExitMessage(), this.taskExecution.getErrorMessage());\n\n\t\t\tthis.finished = true;\n\n\t\t\tif (this.taskProperties.getClosecontextEnabled() && this.context.isActive()) {\n\t\t\t\tthis.context.close();\n\t\t\t}\n\n\t\t}\n\t\telse if (!this.started) {\n\t\t\tlogger.error(\"An event to end a task has been received for a task that has \" + \"not yet started.\");\n\t\t}\n\t}\n\n\tprivate void setExitMessage(TaskExecution taskExecutionParam) {\n\t\tif (taskExecutionParam.getExitMessage() != null) {\n\t\t\tthis.taskExecution.setExitMessage(taskExecutionParam.getExitMessage());\n\t\t}\n\t}\n\n\tprivate int calcExitStatus() {\n\t\tint exitCode = 0;\n\t\tif (this.exitCodeEvent != null) {\n\t\t\texitCode = this.exitCodeEvent.getExitCode();\n\t\t}\n\t\telse if (this.listenerFailed || this.applicationFailedException != null) {\n\t\t\tThrowable exception = this.listenerException;\n\t\t\tif (exception instanceof TaskExecutionException) {\n\t\t\t\tTaskExecutionException taskExecutionException = (TaskExecutionException) exception;\n\t\t\t\tif (taskExecutionException.getCause() instanceof InvocationTargetException) {\n\t\t\t\t\tInvocationTargetException invocationTargetException = (InvocationTargetException) taskExecutionException\n\t\t\t\t\t\t.getCause();\n\t\t\t\t\tif (invocationTargetException != null && invocationTargetException.getTargetException() != null) {\n\t\t\t\t\t\texception = invocationTargetException.getTargetException();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (exception instanceof ExitCodeGenerator) {\n\t\t\t\texitCode = ((ExitCodeGenerator) exception).getExitCode();\n\t\t\t}\n\t\t\telse {\n\t\t\t\texitCode = 1;\n\t\t\t}\n\t\t}\n\n\t\treturn exitCode;\n\t}\n\n\tprivate void doTaskStart() {\n\t\ttry {\n\t\t\tif (!this.started) {\n\t\t\t\tthis.taskExecutionListeners = new ArrayList<>();\n\t\t\t\tthis.taskListenerExecutorObjectFactory.getObject();\n\t\t\t\tif (!CollectionUtils.isEmpty(this.taskExecutionListenersFromContext)) {\n\t\t\t\t\tthis.taskExecutionListeners.addAll(this.taskExecutionListenersFromContext);\n\t\t\t\t}\n\t\t\t\tthis.taskExecutionListeners.add(this.taskListenerExecutorObjectFactory.getObject());\n\n\t\t\t\tList<String> args = new ArrayList<>(0);\n\n\t\t\t\tif (this.applicationArguments != null) {\n\t\t\t\t\targs = Arrays.asList(this.applicationArguments.getSourceArgs());\n\t\t\t\t}\n\t\t\t\tif (this.taskProperties.getExecutionid() != null) {\n\t\t\t\t\tTaskExecution taskExecution = this.taskExplorer\n\t\t\t\t\t\t.getTaskExecution(this.taskProperties.getExecutionid());\n\t\t\t\t\tAssert.notNull(taskExecution, String.format(\"Invalid TaskExecution, ID %s not found\",\n\t\t\t\t\t\t\tthis.taskProperties.getExecutionid()));\n\t\t\t\t\tAssert.isNull(taskExecution.getEndTime(),\n\t\t\t\t\t\t\tString.format(\"Invalid TaskExecution, ID %s task is already complete\",\n\t\t\t\t\t\t\t\t\tthis.taskProperties.getExecutionid()));\n\t\t\t\t\tLocalDateTime startDate = (taskExecution.getStartTime() == null) ? LocalDateTime.now()\n\t\t\t\t\t\t\t: taskExecution.getStartTime();\n\t\t\t\t\tthis.taskExecution = this.taskRepository.startTaskExecution(this.taskProperties.getExecutionid(),\n\t\t\t\t\t\t\tthis.taskNameResolver.getTaskName(), startDate, args,\n\t\t\t\t\t\t\tthis.taskProperties.getExternalExecutionId(), this.taskProperties.getParentExecutionId());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tTaskExecution taskExecution = new TaskExecution();\n\t\t\t\t\ttaskExecution.setTaskName(this.taskNameResolver.getTaskName());\n\t\t\t\t\ttaskExecution.setStartTime(LocalDateTime.now());\n\t\t\t\t\ttaskExecution.setArguments(args);\n\t\t\t\t\ttaskExecution.setExternalExecutionId(this.taskProperties.getExternalExecutionId());\n\t\t\t\t\ttaskExecution.setParentExecutionId(this.taskProperties.getParentExecutionId());\n\t\t\t\t\tthis.taskExecution = this.taskRepository.createTaskExecution(taskExecution);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlogger.error(\"Multiple start events have been received.  The first one was \" + \"recorded.\");\n\t\t\t}\n\n\t\t\tsetExitMessage(invokeOnTaskStartup(this.taskExecution));\n\t\t}\n\t\tcatch (Throwable t) {\n\t\t\t// This scenario will result in a context that was not startup.\n\t\t\tthis.applicationFailedException = t;\n\t\t\tthis.doTaskEnd();\n\t\t\tthrow t;\n\t\t}\n\t}\n\n\tprivate TaskExecution invokeOnTaskStartup(TaskExecution taskExecution) {\n\t\tthis.taskObservations.onTaskStartup(taskExecution);\n\t\tTaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution);\n\t\tList<TaskExecutionListener> startupListenerList = new ArrayList<>(this.taskExecutionListeners);\n\t\tif (!CollectionUtils.isEmpty(startupListenerList)) {\n\t\t\ttry {\n\t\t\t\tCollections.reverse(startupListenerList);\n\t\t\t\tfor (TaskExecutionListener taskExecutionListener : startupListenerList) {\n\t\t\t\t\ttaskExecutionListener.onTaskStartup(listenerTaskExecution);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Throwable currentListenerException) {\n\t\t\t\tlogger.error(currentListenerException);\n\t\t\t\tthis.listenerFailed = true;\n\t\t\t\tthis.taskExecution.setErrorMessage(currentListenerException.getMessage());\n\t\t\t\tthis.listenerException = currentListenerException;\n\t\t\t\tthrow currentListenerException;\n\t\t\t}\n\t\t}\n\t\treturn listenerTaskExecution;\n\t}\n\n\tprivate TaskExecution invokeOnTaskEnd(TaskExecution taskExecution) {\n\t\tif (this.taskObservations != null) {\n\t\t\tthis.taskObservations.onTaskEnd(taskExecution);\n\t\t}\n\t\tTaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution);\n\t\tif (this.taskExecutionListeners != null) {\n\t\t\ttry {\n\t\t\t\tfor (TaskExecutionListener taskExecutionListener : this.taskExecutionListeners) {\n\t\t\t\t\ttaskExecutionListener.onTaskEnd(listenerTaskExecution);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Throwable listenerException) {\n\t\t\t\tString errorMessage = stackTraceToString(listenerException);\n\t\t\t\tif (StringUtils.hasText(listenerTaskExecution.getErrorMessage())) {\n\t\t\t\t\terrorMessage = String.format(\"%s :Task also threw this Exception: %s\", errorMessage,\n\t\t\t\t\t\t\tlistenerTaskExecution.getErrorMessage());\n\t\t\t\t}\n\t\t\t\tlogger.error(errorMessage);\n\t\t\t\tlistenerTaskExecution.setErrorMessage(errorMessage);\n\t\t\t\tthis.listenerFailed = true;\n\t\t\t}\n\t\t}\n\t\treturn listenerTaskExecution;\n\t}\n\n\tprivate TaskExecution invokeOnTaskError(TaskExecution taskExecution, Throwable throwable) {\n\t\tif (this.taskObservations != null) {\n\t\t\tthis.taskObservations.onTaskFailed(throwable);\n\t\t}\n\t\tTaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution);\n\t\tif (this.taskExecutionListeners != null) {\n\t\t\ttry {\n\t\t\t\tfor (TaskExecutionListener taskExecutionListener : this.taskExecutionListeners) {\n\t\t\t\t\ttaskExecutionListener.onTaskFailed(listenerTaskExecution, throwable);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (Throwable listenerException) {\n\t\t\t\tthis.listenerFailed = true;\n\t\t\t\tString errorMessage;\n\t\t\t\tif (StringUtils.hasText(listenerTaskExecution.getErrorMessage())) {\n\t\t\t\t\terrorMessage = String.format(\"%s :While handling \" + \"this error: %s\",\n\t\t\t\t\t\t\tlistenerException.getMessage(), listenerTaskExecution.getErrorMessage());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\terrorMessage = listenerTaskExecution.getErrorMessage();\n\t\t\t\t}\n\t\t\t\tlogger.error(errorMessage);\n\t\t\t\tlistenerTaskExecution.setErrorMessage(errorMessage);\n\t\t\t\tlistenerTaskExecution.setExitCode(1);\n\t\t\t}\n\n\t\t}\n\t\treturn listenerTaskExecution;\n\t}\n\n\tprivate TaskExecution getTaskExecutionCopy(TaskExecution taskExecution) {\n\t\tLocalDateTime startTime = taskExecution.getStartTime();\n\t\tLocalDateTime endTime = taskExecution.getEndTime();\n\n\t\treturn new TaskExecution(taskExecution.getExecutionId(), taskExecution.getExitCode(),\n\t\t\t\ttaskExecution.getTaskName(), startTime, endTime, taskExecution.getExitMessage(),\n\t\t\t\tCollections.unmodifiableList(taskExecution.getArguments()), taskExecution.getErrorMessage(),\n\t\t\t\ttaskExecution.getExternalExecutionId(), taskExecution.getParentExecutionId());\n\t}\n\n\t@Override\n\tpublic boolean isAutoStartup() {\n\t\treturn true;\n\t}\n\n\t@Override\n\tpublic void stop(Runnable callback) {\n\t\tAssert.notNull(callback, \"A callback is required\");\n\t\tstop();\n\t\tcallback.run();\n\t}\n\n\t@Override\n\tpublic void start() {\n\t\tdoTaskStart();\n\t\tthis.started = true;\n\t}\n\n\t@Override\n\tpublic void stop() {\n\t\tthis.doTaskEnd();\n\t}\n\n\t@Override\n\tpublic boolean isRunning() {\n\t\treturn this.started;\n\t}\n\n\t@Override\n\tpublic int getPhase() {\n\t\treturn 0;\n\t}\n\n\t@Override\n\tpublic void destroy() {\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn HIGHEST_PRECEDENCE;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskListenerExecutorObjectFactory.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Method;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.aop.framework.autoproxy.AutoProxyUtils;\nimport org.springframework.aop.scope.ScopedObject;\nimport org.springframework.aop.scope.ScopedProxyUtils;\nimport org.springframework.beans.factory.BeanInitializationException;\nimport org.springframework.beans.factory.ObjectFactory;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.cloud.task.listener.annotation.AfterTask;\nimport org.springframework.cloud.task.listener.annotation.BeforeTask;\nimport org.springframework.cloud.task.listener.annotation.FailedTask;\nimport org.springframework.cloud.task.listener.annotation.TaskListenerExecutor;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.MethodIntrospector;\nimport org.springframework.core.annotation.AnnotationUtils;\n\n/**\n * Initializes TaskListenerExecutor for a task.\n *\n * @author Glenn Renfro\n * @author Isik Erhan\n * @since 2.1.0\n */\npublic class TaskListenerExecutorObjectFactory implements ObjectFactory<TaskExecutionListener> {\n\n\tprivate static final Log logger = LogFactory.getLog(TaskListenerExecutor.class);\n\n\tprivate final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>());\n\n\tprivate ConfigurableApplicationContext context;\n\n\tprivate Map<Method, Set<Object>> beforeTaskInstances;\n\n\tprivate Map<Method, Set<Object>> afterTaskInstances;\n\n\tprivate Map<Method, Set<Object>> failedTaskInstances;\n\n\tpublic TaskListenerExecutorObjectFactory(ConfigurableApplicationContext context) {\n\t\tthis.context = context;\n\t}\n\n\t@Override\n\tpublic TaskListenerExecutor getObject() {\n\t\tthis.beforeTaskInstances = new HashMap<>();\n\t\tthis.afterTaskInstances = new HashMap<>();\n\t\tthis.failedTaskInstances = new HashMap<>();\n\t\tinitializeExecutor();\n\t\treturn new TaskListenerExecutor(this.beforeTaskInstances, this.afterTaskInstances, this.failedTaskInstances);\n\t}\n\n\tprivate void initializeExecutor() {\n\t\tConfigurableListableBeanFactory factory = this.context.getBeanFactory();\n\t\tfor (String beanName : this.context.getBeanDefinitionNames()) {\n\n\t\t\tif (!ScopedProxyUtils.isScopedTarget(beanName)) {\n\t\t\t\tClass<?> type = null;\n\t\t\t\ttry {\n\t\t\t\t\ttype = AutoProxyUtils.determineTargetClass(factory, beanName);\n\t\t\t\t}\n\t\t\t\tcatch (RuntimeException ex) {\n\t\t\t\t\t// An unresolvable bean type, probably from a lazy bean - let's ignore\n\t\t\t\t\t// it.\n\t\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\t\tlogger.debug(\"Could not resolve target class for bean with name '\" + beanName + \"'\", ex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (type != null) {\n\t\t\t\t\tif (ScopedObject.class.isAssignableFrom(type)) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\ttype = AutoProxyUtils.determineTargetClass(factory,\n\t\t\t\t\t\t\t\t\tScopedProxyUtils.getTargetBeanName(beanName));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (RuntimeException ex) {\n\t\t\t\t\t\t\t// An invalid scoped proxy arrangement - let's ignore it.\n\t\t\t\t\t\t\tif (logger.isDebugEnabled()) {\n\t\t\t\t\t\t\t\tlogger.debug(\"Could not resolve target bean for scoped proxy '\" + beanName + \"'\", ex);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tprocessBean(beanName, type);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (RuntimeException ex) {\n\t\t\t\t\t\tthrow new BeanInitializationException(\n\t\t\t\t\t\t\t\t\"Failed to process @BeforeTask \" + \"annotation on bean with name '\" + beanName + \"'\",\n\t\t\t\t\t\t\t\tex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate void processBean(String beanName, final Class<?> type) {\n\t\tif (!this.nonAnnotatedClasses.contains(type)) {\n\t\t\tMap<Method, BeforeTask> beforeTaskMethods = (new MethodGetter<BeforeTask>()).getMethods(type,\n\t\t\t\t\tBeforeTask.class);\n\t\t\tMap<Method, AfterTask> afterTaskMethods = (new MethodGetter<AfterTask>()).getMethods(type, AfterTask.class);\n\t\t\tMap<Method, FailedTask> failedTaskMethods = (new MethodGetter<FailedTask>()).getMethods(type,\n\t\t\t\t\tFailedTask.class);\n\n\t\t\tif (beforeTaskMethods.isEmpty() && afterTaskMethods.isEmpty()) {\n\t\t\t\tthis.nonAnnotatedClasses.add(type);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!beforeTaskMethods.isEmpty()) {\n\t\t\t\tfor (Method beforeTaskMethod : beforeTaskMethods.keySet()) {\n\t\t\t\t\tthis.beforeTaskInstances.computeIfAbsent(beforeTaskMethod, k -> new LinkedHashSet<>())\n\t\t\t\t\t\t.add(this.context.getBean(beanName));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!afterTaskMethods.isEmpty()) {\n\t\t\t\tfor (Method afterTaskMethod : afterTaskMethods.keySet()) {\n\t\t\t\t\tthis.afterTaskInstances.computeIfAbsent(afterTaskMethod, k -> new LinkedHashSet<>())\n\t\t\t\t\t\t.add(this.context.getBean(beanName));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!failedTaskMethods.isEmpty()) {\n\t\t\t\tfor (Method failedTaskMethod : failedTaskMethods.keySet()) {\n\t\t\t\t\tthis.failedTaskInstances.computeIfAbsent(failedTaskMethod, k -> new LinkedHashSet<>())\n\t\t\t\t\t\t.add(this.context.getBean(beanName));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static final class MethodGetter<T extends Annotation> {\n\n\t\tpublic Map<Method, T> getMethods(final Class<?> type, final Class<T> annotationClass) {\n\t\t\treturn MethodIntrospector.selectMethods(type,\n\t\t\t\t\t(MethodIntrospector.MetadataLookup<T>) method -> AnnotationUtils.findAnnotation(method,\n\t\t\t\t\t\t\tannotationClass));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskObservations.java",
    "content": "/*\n * Copyright 2019-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationConvention;\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.cloud.task.configuration.TaskObservationCloudKeyValues;\nimport org.springframework.cloud.task.repository.TaskExecution;\n\n/**\n * Utility class for publishing Spring Cloud Task specific Observations via Micrometer.\n * Intended for internal use only.\n *\n * @author Christian Tzolov\n * @author Glenn Renfro\n * @since 2.2\n */\npublic class TaskObservations {\n\n\t/**\n\t * Successful task execution status indicator.\n\t */\n\tpublic static final String STATUS_SUCCESS = \"success\";\n\n\t/**\n\t * Failing task execution status indicator.\n\t */\n\tpublic static final String STATUS_FAILURE = \"failure\";\n\n\t/**\n\t * Default for when value is not present.\n\t */\n\tpublic static final String UNKNOWN = \"unknown\";\n\n\tprivate ObservationRegistry observationRegistry;\n\n\tprivate ObservationConvention customObservationConvention;\n\n\tpublic TaskObservations(ObservationRegistry observationRegistry,\n\t\t\tTaskObservationCloudKeyValues taskObservationCloudKeyValues,\n\t\t\tObservationConvention customObservationConvention) {\n\t\tthis.observationRegistry = observationRegistry;\n\t\tthis.taskObservationCloudKeyValues = taskObservationCloudKeyValues;\n\t\tthis.customObservationConvention = customObservationConvention;\n\t}\n\n\tprivate Observation.Scope scope;\n\n\tprivate TaskExecutionObservationConvention observationsProvider = new DefaultTaskExecutionObservationConvention();\n\n\tprivate TaskExecutionObservationContext taskObservationContext;\n\n\tTaskObservationCloudKeyValues taskObservationCloudKeyValues;\n\n\tpublic void onTaskStartup(TaskExecution taskExecution) {\n\n\t\tthis.taskObservationContext = new TaskExecutionObservationContext(taskExecution);\n\n\t\tObservation observation = TaskExecutionObservation.TASK_ACTIVE\n\t\t\t.observation(this.customObservationConvention, new DefaultTaskExecutionObservationConvention(),\n\t\t\t\t\tthis.taskObservationContext, this.observationRegistry)\n\t\t\t.contextualName(String.valueOf(taskExecution.getExecutionId()))\n\t\t\t.observationConvention(this.observationsProvider)\n\t\t\t.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_NAME.asString(),\n\t\t\t\t\tgetValueOrDefault(taskExecution.getTaskName()))\n\t\t\t.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.asString(),\n\t\t\t\t\t\"\" + taskExecution.getExecutionId())\n\t\t\t.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_PARENT_EXECUTION_ID.asString(),\n\t\t\t\t\t(getValueOrDefault(taskExecution.getParentExecutionId())))\n\t\t\t.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_EXTERNAL_EXECUTION_ID.asString(),\n\t\t\t\t\t(getValueOrDefault(taskExecution.getExternalExecutionId())));\n\n\t\tif (taskObservationCloudKeyValues != null) {\n\t\t\tobservation.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_CF_ORG_NAME.asString(),\n\t\t\t\t\tthis.taskObservationCloudKeyValues.getOrganizationName());\n\t\t\tobservation.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_CF_SPACE_ID.asString(),\n\t\t\t\t\tthis.taskObservationCloudKeyValues.getSpaceId());\n\t\t\tobservation.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_CF_SPACE_NAME.asString(),\n\t\t\t\t\tthis.taskObservationCloudKeyValues.getSpaceName());\n\t\t\tobservation.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_ID.asString(),\n\t\t\t\t\tthis.taskObservationCloudKeyValues.getApplicationId());\n\t\t\tobservation.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_NAME.asString(),\n\t\t\t\t\tthis.taskObservationCloudKeyValues.getApplicationName());\n\t\t\tobservation.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_VERSION.asString(),\n\t\t\t\t\tthis.taskObservationCloudKeyValues.getApplicationVersion());\n\t\t\tobservation.lowCardinalityKeyValue(TaskExecutionObservation.TaskKeyValues.TASK_CF_INSTANCE_INDEX.asString(),\n\t\t\t\t\tthis.taskObservationCloudKeyValues.getInstanceIndex());\n\t\t}\n\t\tobservation.start();\n\n\t\tthis.scope = observation.openScope();\n\t}\n\n\tprivate String getValueOrDefault(Object value) {\n\t\treturn (value != null) ? value.toString() : UNKNOWN;\n\t}\n\n\tpublic void onTaskFailed(Throwable throwable) {\n\t\tthis.taskObservationContext.setStatus(STATUS_FAILURE);\n\t\tthis.scope.getCurrentObservation().error(throwable);\n\t}\n\n\tpublic void onTaskEnd(TaskExecution taskExecution) {\n\t\tif (this.scope != null) {\n\t\t\tthis.taskObservationContext.getTaskExecution().setExitCode(taskExecution.getExitCode());\n\t\t\tthis.scope.close();\n\t\t\tthis.scope.getCurrentObservation().stop();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/annotation/AfterTask.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.cloud.task.listener.TaskExecutionListener;\nimport org.springframework.cloud.task.repository.TaskExecution;\n\n/**\n * <p>\n * {@link TaskExecutionListener#onTaskEnd(TaskExecution)}.\n * </p>\n *\n * <pre class=\"code\">\n * public class MyListener {\n * \t&#064;AfterTask\n * \tpublic void  doSomething(TaskExecution taskExecution) {\n *    }\n * }\n * </pre>\n *\n * @author Glenn Renfro\n */\n@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Reflective\npublic @interface AfterTask {\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/annotation/BeforeTask.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.cloud.task.listener.TaskExecutionListener;\nimport org.springframework.cloud.task.repository.TaskExecution;\n\n/**\n * <p>\n * {@link TaskExecutionListener#onTaskStartup(TaskExecution)}.\n * </p>\n *\n * <pre class=\"code\">\n * public class MyListener {\n * \t&#064;BeforeTask\n * \tpublic void  doSomething(TaskExecution taskExecution) {\n *    }\n * }\n * </pre>\n *\n * @author Glenn Renfro\n */\n@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Reflective\npublic @interface BeforeTask {\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/annotation/FailedTask.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener.annotation;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\nimport org.springframework.aot.hint.annotation.Reflective;\nimport org.springframework.cloud.task.listener.TaskExecutionListener;\nimport org.springframework.cloud.task.repository.TaskExecution;\n\n/**\n * <p>\n * {@link TaskExecutionListener#onTaskFailed(TaskExecution, Throwable)}.\n * </p>\n *\n * <pre class=\"code\">\n * public class MyListener {\n * \t&#064;FailedTask\n * \tpublic void  doSomething(TaskExecution taskExecution, Throwable throwable) {\n *    }\n * }\n * </pre>\n *\n * @author Glenn Renfro\n */\n@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })\n@Retention(RetentionPolicy.RUNTIME)\n@Documented\n@Reflective\npublic @interface FailedTask {\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/annotation/TaskListenerExecutor.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener.annotation;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.springframework.cloud.task.listener.TaskExecutionException;\nimport org.springframework.cloud.task.listener.TaskExecutionListener;\nimport org.springframework.cloud.task.repository.TaskExecution;\n\n/**\n * Identifies all beans that contain a TaskExecutionListener annotation and stores the\n * associated method so that it can be called by the {@link TaskExecutionListener} at the\n * appropriate time.\n *\n * @author Glenn Renfro\n * @author Isik Erhan\n */\npublic class TaskListenerExecutor implements TaskExecutionListener {\n\n\tprivate Map<Method, Set<Object>> beforeTaskInstances;\n\n\tprivate Map<Method, Set<Object>> afterTaskInstances;\n\n\tprivate Map<Method, Set<Object>> failedTaskInstances;\n\n\tpublic TaskListenerExecutor(Map<Method, Set<Object>> beforeTaskInstances,\n\t\t\tMap<Method, Set<Object>> afterTaskInstances, Map<Method, Set<Object>> failedTaskInstances) {\n\n\t\tthis.beforeTaskInstances = beforeTaskInstances;\n\t\tthis.afterTaskInstances = afterTaskInstances;\n\t\tthis.failedTaskInstances = failedTaskInstances;\n\t}\n\n\t/**\n\t * Executes all the methods that have been annotated with &#064;BeforeTask.\n\t * @param taskExecution associated with the event.\n\t */\n\t@Override\n\tpublic void onTaskStartup(TaskExecution taskExecution) {\n\t\texecuteTaskListener(taskExecution, this.beforeTaskInstances.keySet(), this.beforeTaskInstances);\n\t}\n\n\t/**\n\t * Executes all the methods that have been annotated with &#064;AfterTask.\n\t * @param taskExecution associated with the event.\n\t */\n\t@Override\n\tpublic void onTaskEnd(TaskExecution taskExecution) {\n\t\texecuteTaskListener(taskExecution, this.afterTaskInstances.keySet(), this.afterTaskInstances);\n\t}\n\n\t/**\n\t * Executes all the methods that have been annotated with &#064;FailedTask.\n\t * @param throwable that was not caught for the task execution.\n\t * @param taskExecution associated with the event.\n\t */\n\t@Override\n\tpublic void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {\n\t\texecuteTaskListenerWithThrowable(taskExecution, throwable, this.failedTaskInstances.keySet(),\n\t\t\t\tthis.failedTaskInstances);\n\t}\n\n\tprivate void executeTaskListener(TaskExecution taskExecution, Set<Method> methods,\n\t\t\tMap<Method, Set<Object>> instances) {\n\t\tfor (Method method : methods) {\n\t\t\tfor (Object instance : instances.get(method)) {\n\t\t\t\ttry {\n\t\t\t\t\tmethod.invoke(instance, taskExecution);\n\t\t\t\t}\n\t\t\t\tcatch (IllegalAccessException e) {\n\t\t\t\t\tthrow new TaskExecutionException(\"@BeforeTask and @AfterTask annotated methods must be public.\", e);\n\t\t\t\t}\n\t\t\t\tcatch (InvocationTargetException e) {\n\t\t\t\t\tthrow new TaskExecutionException(\n\t\t\t\t\t\t\tString.format(\"Failed to process @BeforeTask or @AfterTask\" + \" annotation because: %s\",\n\t\t\t\t\t\t\t\t\te.getTargetException().getMessage()),\n\t\t\t\t\t\t\te);\n\t\t\t\t}\n\t\t\t\tcatch (IllegalArgumentException e) {\n\t\t\t\t\tthrow new TaskExecutionException(\n\t\t\t\t\t\t\t\"taskExecution parameter \" + \"is required for @BeforeTask and @AfterTask annotated methods\",\n\t\t\t\t\t\t\te);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate void executeTaskListenerWithThrowable(TaskExecution taskExecution, Throwable throwable, Set<Method> methods,\n\t\t\tMap<Method, Set<Object>> instances) {\n\t\tfor (Method method : methods) {\n\t\t\tfor (Object instance : instances.get(method)) {\n\t\t\t\ttry {\n\t\t\t\t\tmethod.invoke(instance, taskExecution, throwable);\n\t\t\t\t}\n\t\t\t\tcatch (IllegalAccessException e) {\n\t\t\t\t\tthrow new TaskExecutionException(\"@FailedTask annotated methods must be public.\", e);\n\t\t\t\t}\n\t\t\t\tcatch (InvocationTargetException e) {\n\t\t\t\t\tthrow new TaskExecutionException(\n\t\t\t\t\t\t\tString.format(\"Failed to process @FailedTask \" + \"annotation because: %s\",\n\t\t\t\t\t\t\t\t\te.getTargetException().getMessage()),\n\t\t\t\t\t\t\te);\n\t\t\t\t}\n\t\t\t\tcatch (IllegalArgumentException e) {\n\t\t\t\t\tthrow new TaskExecutionException(\"taskExecution and throwable parameters \"\n\t\t\t\t\t\t\t+ \"are required for @FailedTask annotated methods\", e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/annotation/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Annotation-based listener support for Spring Cloud Task.\n */\npackage org.springframework.cloud.task.listener.annotation;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Task lifecycle listener support for Spring Cloud Task.\n */\npackage org.springframework.cloud.task.listener;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Base package for spring cloud task.\n */\npackage org.springframework.cloud.task;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskExecution.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository;\n\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.util.Assert;\n\n/**\n * Represents the state of the Task for each execution.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @author Ilayaperumal Gopinathan\n */\n\npublic class TaskExecution {\n\n\t/**\n\t * The unique id associated with the task execution.\n\t */\n\tprivate long executionId;\n\n\t/**\n\t * The parent task execution id.\n\t */\n\tprivate Long parentExecutionId;\n\n\t/**\n\t * The recorded exit code for the task.\n\t */\n\tprivate Integer exitCode;\n\n\t/**\n\t * User defined name for the task.\n\t */\n\tprivate String taskName;\n\n\t/**\n\t * Time of when the task was started.\n\t */\n\tprivate LocalDateTime startTime;\n\n\t/**\n\t * Timestamp of when the task was completed/terminated.\n\t */\n\tprivate LocalDateTime endTime;\n\n\t/**\n\t * Message returned from the task or stacktrace.\n\t */\n\tprivate String exitMessage;\n\n\t/**\n\t * Id assigned to the task by the platform.\n\t *\n\t * @since 1.1.0\n\t */\n\tprivate String externalExecutionId;\n\n\t/**\n\t * Error information available upon the failure of a task.\n\t *\n\t * @since 1.1.0\n\t */\n\tprivate String errorMessage;\n\n\t/**\n\t * The arguments that were used for this task execution.\n\t */\n\tprivate List<String> arguments;\n\n\tpublic TaskExecution() {\n\t\tthis.arguments = new ArrayList<>();\n\t}\n\n\tpublic TaskExecution(long executionId, Integer exitCode, String taskName, LocalDateTime startTime,\n\t\t\tLocalDateTime endTime, String exitMessage, List<String> arguments, String errorMessage,\n\t\t\tString externalExecutionId, Long parentExecutionId) {\n\n\t\tAssert.notNull(arguments, \"arguments must not be null\");\n\t\tthis.executionId = executionId;\n\t\tthis.exitCode = exitCode;\n\t\tthis.taskName = taskName;\n\t\tthis.exitMessage = exitMessage;\n\t\tthis.arguments = new ArrayList<>(arguments);\n\t\tthis.startTime = startTime;\n\t\tthis.endTime = endTime;\n\t\tthis.errorMessage = errorMessage;\n\t\tthis.externalExecutionId = externalExecutionId;\n\t\tthis.parentExecutionId = parentExecutionId;\n\t}\n\n\tpublic TaskExecution(long executionId, Integer exitCode, String taskName, LocalDateTime startTime,\n\t\t\tLocalDateTime endTime, String exitMessage, List<String> arguments, String errorMessage,\n\t\t\tString externalExecutionId) {\n\n\t\tthis(executionId, exitCode, taskName, startTime, endTime, exitMessage, arguments, errorMessage,\n\t\t\t\texternalExecutionId, null);\n\t}\n\n\tpublic long getExecutionId() {\n\t\treturn this.executionId;\n\t}\n\n\tpublic Integer getExitCode() {\n\t\treturn this.exitCode;\n\t}\n\n\tpublic void setExitCode(Integer exitCode) {\n\t\tthis.exitCode = exitCode;\n\t}\n\n\tpublic String getTaskName() {\n\t\treturn this.taskName;\n\t}\n\n\tpublic void setTaskName(String taskName) {\n\t\tthis.taskName = taskName;\n\t}\n\n\tpublic LocalDateTime getStartTime() {\n\t\treturn this.startTime;\n\t}\n\n\tpublic void setStartTime(LocalDateTime startTime) {\n\t\tthis.startTime = startTime;\n\t}\n\n\tpublic LocalDateTime getEndTime() {\n\t\treturn this.endTime;\n\t}\n\n\tpublic void setEndTime(LocalDateTime endTime) {\n\t\tthis.endTime = endTime;\n\t}\n\n\tpublic String getExitMessage() {\n\t\treturn this.exitMessage;\n\t}\n\n\tpublic void setExitMessage(String exitMessage) {\n\t\tthis.exitMessage = exitMessage;\n\t}\n\n\tpublic List<String> getArguments() {\n\t\treturn this.arguments;\n\t}\n\n\tpublic void setArguments(List<String> arguments) {\n\t\tthis.arguments = new ArrayList<>(arguments);\n\t}\n\n\tpublic String getErrorMessage() {\n\t\treturn this.errorMessage;\n\t}\n\n\tpublic void setErrorMessage(String errorMessage) {\n\t\tthis.errorMessage = errorMessage;\n\t}\n\n\tpublic String getExternalExecutionId() {\n\t\treturn this.externalExecutionId;\n\t}\n\n\tpublic void setExternalExecutionId(String externalExecutionId) {\n\t\tthis.externalExecutionId = externalExecutionId;\n\t}\n\n\tpublic Long getParentExecutionId() {\n\t\treturn this.parentExecutionId;\n\t}\n\n\tpublic void setParentExecutionId(Long parentExecutionId) {\n\t\tthis.parentExecutionId = parentExecutionId;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"TaskExecution{\" + \"executionId=\" + this.executionId + \", parentExecutionId=\" + this.parentExecutionId\n\t\t\t\t+ \", exitCode=\" + this.exitCode + \", taskName='\" + this.taskName + '\\'' + \", startTime=\"\n\t\t\t\t+ this.startTime + \", endTime=\" + this.endTime + \", exitMessage='\" + this.exitMessage + '\\''\n\t\t\t\t+ \", externalExecutionId='\" + this.externalExecutionId + '\\'' + \", errorMessage='\" + this.errorMessage\n\t\t\t\t+ '\\'' + \", arguments=\" + this.arguments + '}';\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskExplorer.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\n\n/**\n * Offers methods that allow users to query the task executions that are available.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @author Gunnar Hillert\n */\npublic interface TaskExplorer {\n\n\t/**\n\t * Retrieve a {@link TaskExecution} by its id.\n\t * @param executionId the task execution id\n\t * @return the {@link TaskExecution} with this id, or null if not found\n\t */\n\tTaskExecution getTaskExecution(long executionId);\n\n\t/**\n\t * Retrieve a collection of taskExecutions that have the task name provided.\n\t * @param taskName the name of the task\n\t * @param pageable the constraints for the search\n\t * @return the set of running executions for tasks with the specified name\n\t */\n\tPage<TaskExecution> findRunningTaskExecutions(String taskName, Pageable pageable);\n\n\t/**\n\t * Retrieve a collection of taskExecutions that contain the provided external\n\t * execution id.\n\t * @param externalExecutionId the external execution id of the tasks\n\t * @param pageable the constraints for the search\n\t * @return the set of task executions for tasks with the external execution id\n\t */\n\tPage<TaskExecution> findTaskExecutionsByExecutionId(String externalExecutionId, Pageable pageable);\n\n\t/**\n\t * Retrieve a list of available task names.\n\t * @return the set of task names that have been executed\n\t */\n\tList<String> getTaskNames();\n\n\t/**\n\t * Get number of executions for a taskName.\n\t * @param taskName the name of the task to be searched\n\t * @return the number of running tasks that have the taskname specified\n\t */\n\tlong getTaskExecutionCountByTaskName(String taskName);\n\n\t/**\n\t * Retrieves current number of task executions.\n\t * @return current number of task executions.\n\t */\n\tlong getTaskExecutionCount();\n\n\t/**\n\t * Retrieves current number of running task executions.\n\t * @return current number of running task executions.\n\t */\n\tlong getRunningTaskExecutionCount();\n\n\t/**\n\t * Retrieves current number of task executions by external executionId.\n\t * @param externalExecutionId The externalExecutionId to be searched.\n\t * @return current number of task executions for a specific externalExecutionId.\n\t */\n\tlong getTaskExecutionCountByExternalExecutionId(String externalExecutionId);\n\n\t/**\n\t * Get a collection/page of executions.\n\t * @param taskName the name of the task to be searched\n\t * @param pageable the constraints for the search\n\t * @return list of task executions\n\t */\n\tPage<TaskExecution> findTaskExecutionsByName(String taskName, Pageable pageable);\n\n\t/**\n\t * Retrieves all the task executions within the pageable constraints sorted by start\n\t * date descending, taskExecution id descending.\n\t * @param pageable the constraints for the search\n\t * @return page containing the results from the search\n\t */\n\tPage<TaskExecution> findAll(Pageable pageable);\n\n\t/**\n\t * Returns the id of the TaskExecution that the requested Spring Batch job execution\n\t * was executed within the context of. Returns null if none were found.\n\t * @param jobExecutionId the id of the JobExecution\n\t * @return the id of the {@link TaskExecution}\n\t */\n\tLong getTaskExecutionIdByJobExecutionId(long jobExecutionId);\n\n\t/**\n\t * Returns a Set of JobExecution ids for the jobs that were executed within the scope\n\t * of the requested task.\n\t * @param taskExecutionId id of the {@link TaskExecution}\n\t * @return a <code>Set</code> of the ids of the job executions executed within the\n\t * task.\n\t */\n\tSet<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId);\n\n\t/**\n\t * Returns a {@link List} of the latest {@link TaskExecution} for 1 or more task\n\t * names.\n\t *\n\t * Latest is defined by the most recent start time. A {@link TaskExecution} does not\n\t * have to be finished (The results may including pending {@link TaskExecution}s).\n\t *\n\t * It is theoretically possible that a {@link TaskExecution} with the same name to\n\t * have more than 1 {@link TaskExecution} for the exact same start time. In that case\n\t * the {@link TaskExecution} with the highest Task Execution ID is returned.\n\t *\n\t * This method will not consider end times in its calculations. Thus, when a task\n\t * execution {@code A} starts after task execution {@code B} but finishes BEFORE task\n\t * execution {@code A}, then task execution {@code B} is being returned.\n\t * @param taskNames At least 1 task name must be provided\n\t * @return List of TaskExecutions. May be empty but never null.\n\t */\n\tList<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames);\n\n\t/**\n\t * Returns the latest task execution for a given task name. Will ultimately apply the\n\t * same algorithm underneath as {@link #getLatestTaskExecutionsByTaskNames(String...)}\n\t * but will only return a single result.\n\t * @param taskName Must not be null or empty\n\t * @return The latest Task Execution or null\n\t * @see #getLatestTaskExecutionsByTaskNames(String...)\n\t */\n\tTaskExecution getLatestTaskExecutionForTaskName(String taskName);\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskNameResolver.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository;\n\n/**\n * Strategy interface for customizing how the name of a task is determined.\n *\n * @author Michael Minella\n */\npublic interface TaskNameResolver {\n\n\t/**\n\t * @return the name of the task being executed within this context.\n\t */\n\tString getTaskName();\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskRepository.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository;\n\nimport java.time.LocalDateTime;\nimport java.util.List;\n\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * TaskRepository interface offers methods that create and update task execution\n * information.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @author Mahmoud Ben Hassine\n */\npublic interface TaskRepository {\n\n\t/**\n\t * Notifies the repository that a taskExecution has completed.\n\t * @param executionId to the task execution to be updated.\n\t * @param exitCode to be stored for this task.\n\t * @param endTime designated when the task completed.\n\t * @param exitMessage to be stored for the task.\n\t * @return the updated {@link TaskExecution}\n\t */\n\t@Transactional(\"${spring.cloud.task.transaction-manager:springCloudTaskTransactionManager}\")\n\tTaskExecution completeTaskExecution(long executionId, Integer exitCode, LocalDateTime endTime, String exitMessage);\n\n\t/**\n\t * Notifies the repository that a taskExecution has completed.\n\t * @param executionId to the task execution to be updated.\n\t * @param exitCode to be stored for this task execution.\n\t * @param endTime designated when the task completed.\n\t * @param exitMessage to be stored for the task execution.\n\t * @param errorMessage to be stored for the task execution.\n\t * @return the updated {@link TaskExecution}\n\t * @since 1.1.0\n\t */\n\t@Transactional(\"${spring.cloud.task.transaction-manager:springCloudTaskTransactionManager}\")\n\tTaskExecution completeTaskExecution(long executionId, Integer exitCode, LocalDateTime endTime, String exitMessage,\n\t\t\tString errorMessage);\n\n\t/**\n\t * Notifies the repository that a taskExecution needs to be created.\n\t * @param taskExecution a TaskExecution instance containing the startTime, arguments\n\t * and externalExecutionId that will be stored in the repository. Only the values\n\t * enumerated above will be stored for this TaskExecution.\n\t * @return the {@link TaskExecution} that was stored in the repository. The\n\t * TaskExecution's taskExecutionId will also contain the id that was used to store the\n\t * TaskExecution.\n\t */\n\t@Transactional(\"${spring.cloud.task.transaction-manager:springCloudTaskTransactionManager}\")\n\tTaskExecution createTaskExecution(TaskExecution taskExecution);\n\n\t/**\n\t * Creates an empty TaskExecution with just an id and name provided. This is intended\n\t * to be utilized in systems where the request of launching a task is separate from\n\t * the actual start of a task (the underlying system may need to deploy the task prior\n\t * to launching, etc).\n\t * @param name task name to be associated with the task execution.\n\t * @return the initial {@link TaskExecution}\n\t */\n\t@Transactional(\"${spring.cloud.task.transaction-manager:springCloudTaskTransactionManager}\")\n\tTaskExecution createTaskExecution(String name);\n\n\t/**\n\t * Creates an empty TaskExecution with just an id provided. This is intended to be\n\t * utilized in systems where the request of launching a task is separate from the\n\t * actual start of a task (the underlying system may need to deploy the task prior to\n\t * launching, etc).\n\t * @return the initial {@link TaskExecution}\n\t */\n\t@Transactional(\"${spring.cloud.task.transaction-manager:springCloudTaskTransactionManager}\")\n\tTaskExecution createTaskExecution();\n\n\t/**\n\t * Notifies the repository that a taskExecution has has started.\n\t * @param executionid to the task execution to be updated.\n\t * @param taskName the name that associated with the task execution.\n\t * @param startTime the time task began.\n\t * @param arguments list of key/value pairs that configure the task.\n\t * @param externalExecutionId id assigned to the task by the platform.\n\t * @return TaskExecution created based on the parameters.\n\t */\n\t@Transactional(\"${spring.cloud.task.transaction-manager:springCloudTaskTransactionManager}\")\n\tTaskExecution startTaskExecution(long executionid, String taskName, LocalDateTime startTime, List<String> arguments,\n\t\t\tString externalExecutionId);\n\n\t/**\n\t * Notifies the repository to update the taskExecution's externalExecutionId.\n\t * @param executionid to the task execution to be updated.\n\t * @param externalExecutionId id assigned to the task by the platform.\n\t */\n\t@Transactional(\"${spring.cloud.task.transaction-manager:springCloudTaskTransactionManager}\")\n\tvoid updateExternalExecutionId(long executionid, String externalExecutionId);\n\n\t/**\n\t * Notifies the repository that a taskExecution has has started.\n\t * @param executionid to the task execution to be updated.\n\t * @param taskName the name that associated with the task execution.\n\t * @param startTime the time task began.\n\t * @param arguments list of key/value pairs that configure the task.\n\t * @param externalExecutionId id assigned to the task by the platform.\n\t * @param parentExecutionId the parent task execution id.\n\t * @return A TaskExecution that contains the information available at the beginning of\n\t * a TaskExecution.\n\t */\n\t@Transactional(\"${spring.cloud.task.transaction-manager:springCloudTaskTransactionManager}\")\n\tTaskExecution startTaskExecution(long executionid, String taskName, LocalDateTime startTime, List<String> arguments,\n\t\t\tString externalExecutionId, Long parentExecutionId);\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/JdbcTaskExecutionDao.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.dao;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Timestamp;\nimport java.sql.Types;\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.batch.infrastructure.item.database.Order;\nimport org.springframework.cloud.task.configuration.TaskProperties;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.cloud.task.repository.database.support.SqlPagingQueryProviderFactoryBean;\nimport org.springframework.dao.DataAccessException;\nimport org.springframework.dao.EmptyResultDataAccessException;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageImpl;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.jdbc.core.ResultSetExtractor;\nimport org.springframework.jdbc.core.RowCallbackHandler;\nimport org.springframework.jdbc.core.RowMapper;\nimport org.springframework.jdbc.core.namedparam.MapSqlParameterSource;\nimport org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;\nimport org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;\nimport org.springframework.util.Assert;\nimport org.springframework.util.CollectionUtils;\nimport org.springframework.util.StringUtils;\n\n/**\n * Stores Task Execution Information to a JDBC DataSource.\n *\n * @author Glenn Renfro\n * @author Gunnar Hillert\n * @author David Turanski\n * @author Ilayaperumal Gopinathan\n * @author Michael Minella\n */\npublic class JdbcTaskExecutionDao implements TaskExecutionDao {\n\n\t/**\n\t * SELECT clause for task execution.\n\t */\n\tpublic static final String SELECT_CLAUSE = \"TASK_EXECUTION_ID, \" + \"START_TIME, END_TIME, TASK_NAME, EXIT_CODE, \"\n\t\t\t+ \"EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, \" + \"EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID \";\n\n\t/**\n\t * FROM clause for task execution.\n\t */\n\tpublic static final String FROM_CLAUSE = \"%PREFIX%EXECUTION\";\n\n\t/**\n\t * WHERE clause for running task.\n\t */\n\tpublic static final String RUNNING_TASK_WHERE_CLAUSE = \"where TASK_NAME = :taskName AND END_TIME IS NULL \";\n\n\t/**\n\t * WHERE clause for task name.\n\t */\n\tpublic static final String TASK_NAME_WHERE_CLAUSE = \"where TASK_NAME = :taskName \";\n\n\t/**\n\t * WHERE clause for external execution id.\n\t */\n\tpublic static final String EXTERNAL_EXECUTION_ID_WHERE_CLAUSE = \"where EXTERNAL_EXECUTION_ID = :externalExecutionId \";\n\n\tprivate static final String SAVE_TASK_EXECUTION = \"INSERT into %PREFIX%EXECUTION\"\n\t\t\t+ \"(TASK_EXECUTION_ID, EXIT_CODE, START_TIME, TASK_NAME, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID)\"\n\t\t\t+ \"values (:taskExecutionId, :exitCode, :startTime, \"\n\t\t\t+ \":taskName, :lastUpdated, :externalExecutionId, :parentExecutionId)\";\n\n\tprivate static final String CREATE_TASK_ARGUMENT = \"INSERT into \"\n\t\t\t+ \"%PREFIX%EXECUTION_PARAMS(TASK_EXECUTION_ID, TASK_PARAM ) values (:taskExecutionId, :taskParam)\";\n\n\tprivate static final String START_TASK_EXECUTION_PREFIX = \"UPDATE %PREFIX%EXECUTION set \"\n\t\t\t+ \"START_TIME = :startTime, TASK_NAME = :taskName, LAST_UPDATED = :lastUpdated\";\n\n\tprivate static final String START_TASK_EXECUTION_EXTERNAL_ID_SUFFIX = \", \"\n\t\t\t+ \"EXTERNAL_EXECUTION_ID = :externalExecutionId, PARENT_EXECUTION_ID = :parentExecutionId \"\n\t\t\t+ \"where TASK_EXECUTION_ID = :taskExecutionId\";\n\n\tprivate static final String START_TASK_EXECUTION_SUFFIX = \", PARENT_EXECUTION_ID = :parentExecutionId \"\n\t\t\t+ \"where TASK_EXECUTION_ID = :taskExecutionId\";\n\n\tprivate static final String CHECK_TASK_EXECUTION_EXISTS = \"SELECT COUNT(*) FROM \"\n\t\t\t+ \"%PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = :taskExecutionId\";\n\n\tprivate static final String UPDATE_TASK_EXECUTION = \"UPDATE %PREFIX%EXECUTION set \"\n\t\t\t+ \"END_TIME = :endTime, EXIT_CODE = :exitCode, EXIT_MESSAGE = :exitMessage, ERROR_MESSAGE = :errorMessage, \"\n\t\t\t+ \"LAST_UPDATED = :lastUpdated where TASK_EXECUTION_ID = :taskExecutionId\";\n\n\tprivate static final String UPDATE_TASK_EXECUTION_EXTERNAL_EXECUTION_ID = \"UPDATE %PREFIX%EXECUTION set \"\n\t\t\t+ \"EXTERNAL_EXECUTION_ID = :externalExecutionId where TASK_EXECUTION_ID = :taskExecutionId\";\n\n\tprivate static final String GET_EXECUTION_BY_ID = \"SELECT TASK_EXECUTION_ID, \"\n\t\t\t+ \"START_TIME, END_TIME, TASK_NAME, EXIT_CODE, \"\n\t\t\t+ \"EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, \" + \"PARENT_EXECUTION_ID \"\n\t\t\t+ \"from %PREFIX%EXECUTION where TASK_EXECUTION_ID = :taskExecutionId\";\n\n\tprivate static final String FIND_ARGUMENT_FROM_ID = \"SELECT TASK_EXECUTION_ID, \"\n\t\t\t+ \"TASK_PARAM from %PREFIX%EXECUTION_PARAMS where TASK_EXECUTION_ID = :taskExecutionId\";\n\n\tprivate static final String TASK_EXECUTION_COUNT = \"SELECT COUNT(*) FROM \" + \"%PREFIX%EXECUTION \";\n\n\tprivate static final String TASK_EXECUTION_COUNT_BY_NAME = \"SELECT COUNT(*) FROM \"\n\t\t\t+ \"%PREFIX%EXECUTION where TASK_NAME = :taskName\";\n\n\tprivate static final String TASK_EXECUTION_COUNT_BY_EXTERNAL_EXECUTION_ID = \"SELECT COUNT(*) FROM \"\n\t\t\t+ \"%PREFIX%EXECUTION where EXTERNAL_EXECUTION_ID = :externalExecutionId\";\n\n\tprivate static final String RUNNING_TASK_EXECUTION_COUNT_BY_NAME = \"SELECT COUNT(*) FROM \"\n\t\t\t+ \"%PREFIX%EXECUTION where TASK_NAME = :taskName AND END_TIME IS NULL \";\n\n\tprivate static final String RUNNING_TASK_EXECUTION_COUNT = \"SELECT COUNT(*) FROM \"\n\t\t\t+ \"%PREFIX%EXECUTION where END_TIME IS NULL \";\n\n\tprivate static final String LAST_TASK_EXECUTIONS_BY_TASK_NAMES = \"select TE2.* from (\"\n\t\t\t+ \"select MAX(TE.TASK_EXECUTION_ID) as TASK_EXECUTION_ID, TE.TASK_NAME, TE.START_TIME from (\"\n\t\t\t+ \"select TASK_NAME, MAX(START_TIME) as START_TIME\"\n\t\t\t+ \"      FROM %PREFIX%EXECUTION where TASK_NAME in (:taskNames)\" + \"      GROUP BY TASK_NAME\" + \") TE_MAX \"\n\t\t\t+ \"inner join %PREFIX%EXECUTION TE ON TE.TASK_NAME = TE_MAX.TASK_NAME AND TE.START_TIME = TE_MAX.START_TIME \"\n\t\t\t+ \"group by TE.TASK_NAME, TE.START_TIME\" + \") TE1 \"\n\t\t\t+ \"inner join %PREFIX%EXECUTION TE2 ON TE1.TASK_EXECUTION_ID = TE2.TASK_EXECUTION_ID \"\n\t\t\t+ \"order by TE2.START_TIME DESC, TE2.TASK_EXECUTION_ID DESC\";\n\n\tprivate static final String FIND_TASK_NAMES = \"SELECT distinct TASK_NAME from %PREFIX%EXECUTION order by TASK_NAME\";\n\n\tprivate static final String FIND_TASK_EXECUTION_BY_JOB_EXECUTION_ID = \"SELECT TASK_EXECUTION_ID FROM \"\n\t\t\t+ \"%PREFIX%TASK_BATCH WHERE JOB_EXECUTION_ID = :jobExecutionId\";\n\n\tprivate static final String FIND_JOB_EXECUTION_BY_TASK_EXECUTION_ID = \"SELECT JOB_EXECUTION_ID \"\n\t\t\t+ \"FROM %PREFIX%TASK_BATCH WHERE TASK_EXECUTION_ID = :taskExecutionId\";\n\n\tprivate static final Set<String> validSortColumns = new HashSet<>(10);\n\n\tstatic {\n\t\tvalidSortColumns.add(\"TASK_EXECUTION_ID\");\n\t\tvalidSortColumns.add(\"START_TIME\");\n\t\tvalidSortColumns.add(\"END_TIME\");\n\t\tvalidSortColumns.add(\"TASK_NAME\");\n\t\tvalidSortColumns.add(\"EXIT_CODE\");\n\t\tvalidSortColumns.add(\"EXIT_MESSAGE\");\n\t\tvalidSortColumns.add(\"ERROR_MESSAGE\");\n\t\tvalidSortColumns.add(\"LAST_UPDATED\");\n\t\tvalidSortColumns.add(\"EXTERNAL_EXECUTION_ID\");\n\t\tvalidSortColumns.add(\"PARENT_EXECUTION_ID\");\n\t}\n\n\tprivate final NamedParameterJdbcTemplate jdbcTemplate;\n\n\tprivate String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX;\n\n\tprivate DataSource dataSource;\n\n\tprivate LinkedHashMap<String, Order> orderMap;\n\n\tprivate DataFieldMaxValueIncrementer taskIncrementer;\n\n\t/**\n\t * Initializes the JdbcTaskExecutionDao.\n\t * @param dataSource used by the dao to execute queries and update the tables.\n\t * @param tablePrefix the table prefix to use for this dao.\n\t */\n\tpublic JdbcTaskExecutionDao(DataSource dataSource, String tablePrefix) {\n\t\tthis(dataSource);\n\t\tAssert.hasText(tablePrefix, \"tablePrefix must not be null nor empty\");\n\t\tthis.tablePrefix = tablePrefix;\n\t}\n\n\t/**\n\t * Initializes the JdbTaskExecutionDao and defaults the table prefix to\n\t * {@link TaskProperties#DEFAULT_TABLE_PREFIX}.\n\t * @param dataSource used by the dao to execute queries and update the tables.\n\t */\n\tpublic JdbcTaskExecutionDao(DataSource dataSource) {\n\t\tAssert.notNull(dataSource, \"The dataSource must not be null.\");\n\t\tthis.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);\n\t\tthis.dataSource = dataSource;\n\t\tthis.orderMap = new LinkedHashMap<>();\n\t\tthis.orderMap.put(\"START_TIME\", Order.DESCENDING);\n\t\tthis.orderMap.put(\"TASK_EXECUTION_ID\", Order.DESCENDING);\n\t}\n\n\t@Override\n\tpublic TaskExecution createTaskExecution(String taskName, LocalDateTime startTime, List<String> arguments,\n\t\t\tString externalExecutionId) {\n\t\treturn createTaskExecution(taskName, startTime, arguments, externalExecutionId, null);\n\t}\n\n\t@Override\n\tpublic TaskExecution createTaskExecution(String taskName, LocalDateTime startTime, List<String> arguments,\n\t\t\tString externalExecutionId, Long parentExecutionId) {\n\t\tlong nextExecutionId = getNextExecutionId();\n\n\t\tTaskExecution taskExecution = new TaskExecution(nextExecutionId, null, taskName, startTime, null, null,\n\t\t\t\targuments, null, externalExecutionId, parentExecutionId);\n\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource()\n\t\t\t.addValue(\"taskExecutionId\", nextExecutionId, Types.BIGINT)\n\t\t\t.addValue(\"exitCode\", null, Types.INTEGER)\n\t\t\t.addValue(\"startTime\", startTime == null ? null : Timestamp.valueOf(startTime), Types.TIMESTAMP)\n\t\t\t.addValue(\"taskName\", taskName, Types.VARCHAR)\n\t\t\t.addValue(\"lastUpdated\", Timestamp.valueOf(LocalDateTime.now()), Types.TIMESTAMP)\n\t\t\t.addValue(\"externalExecutionId\", externalExecutionId, Types.VARCHAR)\n\t\t\t.addValue(\"parentExecutionId\", parentExecutionId, Types.BIGINT);\n\n\t\tthis.jdbcTemplate.update(getQuery(SAVE_TASK_EXECUTION), queryParameters);\n\t\tinsertTaskArguments(nextExecutionId, arguments);\n\t\treturn taskExecution;\n\t}\n\n\t@Override\n\tpublic TaskExecution startTaskExecution(long executionId, String taskName, LocalDateTime startTime,\n\t\t\tList<String> arguments, String externalExecutionId) {\n\t\treturn startTaskExecution(executionId, taskName, startTime, arguments, externalExecutionId, null);\n\t}\n\n\t@Override\n\tpublic TaskExecution startTaskExecution(long executionId, String taskName, LocalDateTime startTime,\n\t\t\tList<String> arguments, String externalExecutionId, Long parentExecutionId) {\n\t\tTaskExecution taskExecution = new TaskExecution(executionId, null, taskName, startTime, null, null, arguments,\n\t\t\t\tnull, externalExecutionId, parentExecutionId);\n\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource()\n\t\t\t.addValue(\"startTime\", startTime == null ? null : Timestamp.valueOf(startTime), Types.TIMESTAMP)\n\t\t\t.addValue(\"exitCode\", null, Types.INTEGER)\n\t\t\t.addValue(\"taskName\", taskName, Types.VARCHAR)\n\t\t\t.addValue(\"lastUpdated\", Timestamp.valueOf(LocalDateTime.now()), Types.TIMESTAMP)\n\t\t\t.addValue(\"parentExecutionId\", parentExecutionId, Types.BIGINT)\n\t\t\t.addValue(\"taskExecutionId\", executionId, Types.BIGINT);\n\n\t\tString updateString = START_TASK_EXECUTION_PREFIX;\n\n\t\tif (externalExecutionId == null) {\n\t\t\tupdateString += START_TASK_EXECUTION_SUFFIX;\n\t\t}\n\t\telse {\n\t\t\tupdateString += START_TASK_EXECUTION_EXTERNAL_ID_SUFFIX;\n\t\t\tqueryParameters.addValue(\"externalExecutionId\", externalExecutionId, Types.VARCHAR);\n\t\t}\n\n\t\tthis.jdbcTemplate.update(getQuery(updateString), queryParameters);\n\t\tinsertTaskArguments(executionId, arguments);\n\t\treturn taskExecution;\n\t}\n\n\t@Override\n\tpublic void completeTaskExecution(long taskExecutionId, Integer exitCode, LocalDateTime endTime, String exitMessage,\n\t\t\tString errorMessage) {\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource().addValue(\"taskExecutionId\",\n\t\t\t\ttaskExecutionId, Types.BIGINT);\n\n\t\t// Check if given TaskExecution's Id already exists, if none is found\n\t\t// it is invalid and an exception should be thrown.\n\t\tif (this.jdbcTemplate.queryForObject(getQuery(CHECK_TASK_EXECUTION_EXISTS), queryParameters,\n\t\t\t\tInteger.class) != 1) {\n\t\t\tthrow new IllegalStateException(\"Invalid TaskExecution, ID \" + taskExecutionId + \" not found.\");\n\t\t}\n\n\t\tfinal MapSqlParameterSource parameters = new MapSqlParameterSource()\n\t\t\t.addValue(\"endTime\", endTime == null ? null : Timestamp.valueOf(endTime), Types.TIMESTAMP)\n\t\t\t.addValue(\"exitCode\", exitCode, Types.INTEGER)\n\t\t\t.addValue(\"exitMessage\", exitMessage, Types.VARCHAR)\n\t\t\t.addValue(\"errorMessage\", errorMessage, Types.VARCHAR)\n\t\t\t.addValue(\"lastUpdated\", Timestamp.valueOf(LocalDateTime.now()), Types.TIMESTAMP)\n\t\t\t.addValue(\"taskExecutionId\", taskExecutionId, Types.BIGINT);\n\n\t\tthis.jdbcTemplate.update(getQuery(UPDATE_TASK_EXECUTION), parameters);\n\t}\n\n\t@Override\n\tpublic void completeTaskExecution(long taskExecutionId, Integer exitCode, LocalDateTime endTime,\n\t\t\tString exitMessage) {\n\t\tcompleteTaskExecution(taskExecutionId, exitCode, endTime, exitMessage, null);\n\t}\n\n\t@Override\n\tpublic TaskExecution getTaskExecution(long executionId) {\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource().addValue(\"taskExecutionId\",\n\t\t\t\texecutionId, Types.BIGINT);\n\n\t\ttry {\n\t\t\tTaskExecution taskExecution = this.jdbcTemplate.queryForObject(getQuery(GET_EXECUTION_BY_ID),\n\t\t\t\t\tqueryParameters, new TaskExecutionRowMapper());\n\t\t\ttaskExecution.setArguments(getTaskArguments(executionId));\n\t\t\treturn taskExecution;\n\t\t}\n\t\tcatch (EmptyResultDataAccessException e) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic long getTaskExecutionCountByTaskName(String taskName) {\n\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource().addValue(\"taskName\", taskName,\n\t\t\t\tTypes.VARCHAR);\n\n\t\ttry {\n\t\t\treturn this.jdbcTemplate.queryForObject(getQuery(TASK_EXECUTION_COUNT_BY_NAME), queryParameters,\n\t\t\t\t\tLong.class);\n\t\t}\n\t\tcatch (EmptyResultDataAccessException e) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t@Override\n\tpublic long getRunningTaskExecutionCountByTaskName(String taskName) {\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource().addValue(\"taskName\", taskName,\n\t\t\t\tTypes.VARCHAR);\n\n\t\ttry {\n\t\t\treturn this.jdbcTemplate.queryForObject(getQuery(RUNNING_TASK_EXECUTION_COUNT_BY_NAME), queryParameters,\n\t\t\t\t\tLong.class);\n\t\t}\n\t\tcatch (EmptyResultDataAccessException e) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t@Override\n\tpublic long getRunningTaskExecutionCount() {\n\n\t\ttry {\n\t\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource();\n\t\t\treturn this.jdbcTemplate.queryForObject(getQuery(RUNNING_TASK_EXECUTION_COUNT), queryParameters,\n\t\t\t\t\tLong.class);\n\t\t}\n\t\tcatch (EmptyResultDataAccessException e) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t@Override\n\tpublic List<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames) {\n\t\tAssert.notEmpty(taskNames, \"At least 1 task name must be provided.\");\n\n\t\tfinal List<String> taskNamesAsList = new ArrayList<>();\n\n\t\tfor (String taskName : taskNames) {\n\t\t\tif (StringUtils.hasText(taskName)) {\n\t\t\t\ttaskNamesAsList.add(taskName);\n\t\t\t}\n\t\t}\n\n\t\tAssert.isTrue(taskNamesAsList.size() == taskNames.length,\n\t\t\t\tString.format(\"Task names must not contain any empty elements but %s of %s were empty or null.\",\n\t\t\t\t\t\ttaskNames.length - taskNamesAsList.size(), taskNames.length));\n\n\t\ttry {\n\t\t\tfinal Map<String, List<String>> paramMap = Collections.singletonMap(\"taskNames\", taskNamesAsList);\n\t\t\treturn this.jdbcTemplate.query(getQuery(LAST_TASK_EXECUTIONS_BY_TASK_NAMES), paramMap,\n\t\t\t\t\tnew TaskExecutionRowMapper());\n\t\t}\n\t\tcatch (EmptyResultDataAccessException e) {\n\t\t\treturn Collections.emptyList();\n\t\t}\n\t}\n\n\t@Override\n\tpublic TaskExecution getLatestTaskExecutionForTaskName(String taskName) {\n\t\tAssert.hasText(taskName, \"The task name must not be empty.\");\n\t\tfinal List<TaskExecution> taskExecutions = this.getLatestTaskExecutionsByTaskNames(taskName);\n\t\tif (taskExecutions.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\telse if (taskExecutions.size() == 1) {\n\t\t\treturn taskExecutions.get(0);\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Only expected a single TaskExecution but received \" + taskExecutions.size());\n\t\t}\n\t}\n\n\t@Override\n\tpublic long getTaskExecutionCount() {\n\n\t\ttry {\n\t\t\treturn this.jdbcTemplate.queryForObject(getQuery(TASK_EXECUTION_COUNT), new MapSqlParameterSource(),\n\t\t\t\t\tLong.class);\n\t\t}\n\t\tcatch (EmptyResultDataAccessException e) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findRunningTaskExecutions(String taskName, Pageable pageable) {\n\t\treturn queryForPageableResults(pageable, SELECT_CLAUSE, FROM_CLAUSE, RUNNING_TASK_WHERE_CLAUSE,\n\t\t\t\tnew MapSqlParameterSource(\"taskName\", taskName), getRunningTaskExecutionCountByTaskName(taskName));\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findTaskExecutionsByExternalExecutionId(String externalExecutionId, Pageable pageable) {\n\t\treturn queryForPageableResults(pageable, SELECT_CLAUSE, FROM_CLAUSE, EXTERNAL_EXECUTION_ID_WHERE_CLAUSE,\n\t\t\t\tnew MapSqlParameterSource(\"externalExecutionId\", externalExecutionId),\n\t\t\t\tgetTaskExecutionCountByExternalExecutionId(externalExecutionId));\n\t}\n\n\t@Override\n\tpublic long getTaskExecutionCountByExternalExecutionId(String externalExecutionId) {\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource().addValue(\"externalExecutionId\",\n\t\t\t\texternalExecutionId, Types.VARCHAR);\n\n\t\ttry {\n\t\t\treturn this.jdbcTemplate.queryForObject(getQuery(TASK_EXECUTION_COUNT_BY_EXTERNAL_EXECUTION_ID),\n\t\t\t\t\tqueryParameters, Long.class);\n\t\t}\n\t\tcatch (EmptyResultDataAccessException e) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findTaskExecutionsByName(String taskName, Pageable pageable) {\n\t\treturn queryForPageableResults(pageable, SELECT_CLAUSE, FROM_CLAUSE, TASK_NAME_WHERE_CLAUSE,\n\t\t\t\tnew MapSqlParameterSource(\"taskName\", taskName), getTaskExecutionCountByTaskName(taskName));\n\t}\n\n\t@Override\n\tpublic List<String> getTaskNames() {\n\t\treturn this.jdbcTemplate.queryForList(getQuery(FIND_TASK_NAMES), new MapSqlParameterSource(), String.class);\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findAll(Pageable pageable) {\n\t\treturn queryForPageableResults(pageable, SELECT_CLAUSE, FROM_CLAUSE, null, new MapSqlParameterSource(),\n\t\t\t\tgetTaskExecutionCount());\n\t}\n\n\tpublic void setTaskIncrementer(DataFieldMaxValueIncrementer taskIncrementer) {\n\t\tthis.taskIncrementer = taskIncrementer;\n\t}\n\n\tpublic long getNextExecutionId() {\n\t\treturn this.taskIncrementer.nextLongValue();\n\t}\n\n\t@Override\n\tpublic Long getTaskExecutionIdByJobExecutionId(long jobExecutionId) {\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource().addValue(\"jobExecutionId\",\n\t\t\t\tjobExecutionId, Types.BIGINT);\n\n\t\ttry {\n\t\t\treturn this.jdbcTemplate.queryForObject(getQuery(FIND_TASK_EXECUTION_BY_JOB_EXECUTION_ID), queryParameters,\n\t\t\t\t\tLong.class);\n\t\t}\n\t\tcatch (EmptyResultDataAccessException e) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t@Override\n\tpublic Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId) {\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource().addValue(\"taskExecutionId\",\n\t\t\t\ttaskExecutionId, Types.BIGINT);\n\n\t\ttry {\n\t\t\treturn this.jdbcTemplate.query(getQuery(FIND_JOB_EXECUTION_BY_TASK_EXECUTION_ID), queryParameters,\n\t\t\t\t\tnew ResultSetExtractor<Set<Long>>() {\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic Set<Long> extractData(ResultSet resultSet) throws SQLException, DataAccessException {\n\t\t\t\t\t\t\tSet<Long> jobExecutionIds = new TreeSet<>();\n\n\t\t\t\t\t\t\twhile (resultSet.next()) {\n\t\t\t\t\t\t\t\tjobExecutionIds.add(resultSet.getLong(\"JOB_EXECUTION_ID\"));\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn jobExecutionIds;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t}\n\t\tcatch (DataAccessException e) {\n\t\t\treturn Collections.emptySet();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void updateExternalExecutionId(long taskExecutionId, String externalExecutionId) {\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource()\n\t\t\t.addValue(\"externalExecutionId\", externalExecutionId, Types.VARCHAR)\n\t\t\t.addValue(\"taskExecutionId\", taskExecutionId, Types.BIGINT);\n\n\t\tif (this.jdbcTemplate.update(getQuery(UPDATE_TASK_EXECUTION_EXTERNAL_EXECUTION_ID), queryParameters) != 1) {\n\t\t\tthrow new IllegalStateException(\"Invalid TaskExecution, ID \" + taskExecutionId + \" not found.\");\n\t\t}\n\t}\n\n\tprivate Page<TaskExecution> queryForPageableResults(Pageable pageable, String selectClause, String fromClause,\n\t\t\tString whereClause, MapSqlParameterSource queryParameters, long totalCount) {\n\t\tSqlPagingQueryProviderFactoryBean factoryBean = new SqlPagingQueryProviderFactoryBean();\n\t\tfactoryBean.setSelectClause(selectClause);\n\t\tfactoryBean.setFromClause(fromClause);\n\t\tif (StringUtils.hasText(whereClause)) {\n\t\t\tfactoryBean.setWhereClause(whereClause);\n\t\t}\n\t\tfinal Sort sort = pageable.getSort();\n\t\tfinal LinkedHashMap<String, Order> sortOrderMap = new LinkedHashMap<>();\n\n\t\tif (sort != null) {\n\t\t\tfor (Sort.Order sortOrder : sort) {\n\t\t\t\tif (validSortColumns.contains(sortOrder.getProperty().toUpperCase(Locale.ROOT))) {\n\t\t\t\t\tsortOrderMap.put(sortOrder.getProperty(),\n\t\t\t\t\t\t\tsortOrder.isAscending() ? Order.ASCENDING : Order.DESCENDING);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\tString.format(\"Invalid sort option selected: %s\", sortOrder.getProperty()));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!CollectionUtils.isEmpty(sortOrderMap)) {\n\t\t\tfactoryBean.setSortKeys(sortOrderMap);\n\t\t}\n\t\telse {\n\t\t\tfactoryBean.setSortKeys(this.orderMap);\n\t\t}\n\n\t\tfactoryBean.setDataSource(this.dataSource);\n\t\tPagingQueryProvider pagingQueryProvider;\n\t\ttry {\n\t\t\tpagingQueryProvider = factoryBean.getObject();\n\t\t\tpagingQueryProvider.init(this.dataSource);\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tthrow new IllegalStateException(e);\n\t\t}\n\t\tString query = pagingQueryProvider.getPageQuery(pageable);\n\t\tList<TaskExecution> resultList = this.jdbcTemplate.query(getQuery(query), queryParameters,\n\t\t\t\tnew TaskExecutionRowMapper());\n\t\treturn new PageImpl<>(resultList, pageable, totalCount);\n\t}\n\n\tprivate String getQuery(String base) {\n\t\treturn StringUtils.replace(base, \"%PREFIX%\", this.tablePrefix);\n\t}\n\n\t/**\n\t * Convenience method that inserts all arguments from the provided task arguments.\n\t * @param executionId The executionId to which the arguments are associated.\n\t * @param taskArguments The arguments to be stored.\n\t */\n\tprivate void insertTaskArguments(long executionId, List<String> taskArguments) {\n\t\tfor (String args : taskArguments) {\n\t\t\tinsertArgument(executionId, args);\n\t\t}\n\t}\n\n\t/**\n\t * Convenience method that inserts an individual records into the\n\t * TASK_EXECUTION_PARAMS table.\n\t * @param taskExecutionId id of a task execution\n\t * @param taskParam task parameters\n\t */\n\tprivate void insertArgument(long taskExecutionId, String taskParam) {\n\t\tfinal MapSqlParameterSource queryParameters = new MapSqlParameterSource()\n\t\t\t.addValue(\"taskExecutionId\", taskExecutionId, Types.BIGINT)\n\t\t\t.addValue(\"taskParam\", taskParam, Types.VARCHAR);\n\t\tthis.jdbcTemplate.update(getQuery(CREATE_TASK_ARGUMENT), queryParameters);\n\t}\n\n\tprivate List<String> getTaskArguments(long taskExecutionId) {\n\t\tfinal List<String> params = new ArrayList<>();\n\t\tRowCallbackHandler handler = new RowCallbackHandler() {\n\t\t\t@Override\n\t\t\tpublic void processRow(ResultSet rs) throws SQLException {\n\t\t\t\tparams.add(rs.getString(2));\n\t\t\t}\n\t\t};\n\t\tthis.jdbcTemplate.query(getQuery(FIND_ARGUMENT_FROM_ID),\n\t\t\t\tnew MapSqlParameterSource(\"taskExecutionId\", taskExecutionId), handler);\n\t\treturn params;\n\t}\n\n\t/**\n\t * Re-usable mapper for {@link TaskExecution} instances.\n\t *\n\t */\n\tprivate final class TaskExecutionRowMapper implements RowMapper<TaskExecution> {\n\n\t\tprivate TaskExecutionRowMapper() {\n\t\t}\n\n\t\t@Override\n\t\tpublic TaskExecution mapRow(ResultSet rs, int rowNum) throws SQLException {\n\t\t\tlong id = rs.getLong(\"TASK_EXECUTION_ID\");\n\t\t\tLong parentExecutionId = rs.getLong(\"PARENT_EXECUTION_ID\");\n\t\t\tif (rs.wasNull()) {\n\t\t\t\tparentExecutionId = null;\n\t\t\t}\n\t\t\tLocalDateTime startTime = null;\n\t\t\tLocalDateTime endTime = null;\n\t\t\ttry {\n\t\t\t\tstartTime = rs.getObject(\"START_TIME\", LocalDateTime.class);\n\t\t\t}\n\t\t\tcatch (NullPointerException npe) {\n\t\t\t\tif (!npe.getMessage().contains(\"<local4>\")) {\n\t\t\t\t\tthrow npe;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tendTime = rs.getObject(\"END_TIME\", LocalDateTime.class);\n\t\t\t}\n\t\t\tcatch (NullPointerException npe) {\n\t\t\t\tif (!npe.getMessage().contains(\"<local4>\")) {\n\t\t\t\t\tthrow npe;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn new TaskExecution(id, getNullableExitCode(rs), rs.getString(\"TASK_NAME\"), startTime, endTime,\n\t\t\t\t\trs.getString(\"EXIT_MESSAGE\"), getTaskArguments(id), rs.getString(\"ERROR_MESSAGE\"),\n\t\t\t\t\trs.getString(\"EXTERNAL_EXECUTION_ID\"), parentExecutionId);\n\t\t}\n\n\t\tprivate Integer getNullableExitCode(ResultSet rs) throws SQLException {\n\t\t\tint exitCode = rs.getInt(\"EXIT_CODE\");\n\t\t\treturn !rs.wasNull() ? exitCode : null;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/MapTaskExecutionDao.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.dao;\n\nimport java.io.Serializable;\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageImpl;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Stores Task Execution Information to a in-memory map.\n *\n * @author Glenn Renfro\n * @author Gunnar Hillert\n * @author David Turanski\n */\npublic class MapTaskExecutionDao implements TaskExecutionDao {\n\n\tprivate final AtomicLong currentId = new AtomicLong(0L);\n\n\tprivate ConcurrentMap<Long, TaskExecution> taskExecutions;\n\n\tprivate ConcurrentMap<Long, Set<Long>> batchJobAssociations;\n\n\tpublic MapTaskExecutionDao() {\n\t\tthis.taskExecutions = new ConcurrentHashMap<>();\n\t\tthis.batchJobAssociations = new ConcurrentHashMap<>();\n\t}\n\n\t@Override\n\tpublic TaskExecution createTaskExecution(String taskName, LocalDateTime startTime, List<String> arguments,\n\t\t\tString externalExecutionId) {\n\t\treturn createTaskExecution(taskName, startTime, arguments, externalExecutionId, null);\n\t}\n\n\t@Override\n\tpublic TaskExecution createTaskExecution(String taskName, LocalDateTime startTime, List<String> arguments,\n\t\t\tString externalExecutionId, Long parentExecutionId) {\n\t\tlong taskExecutionId = getNextExecutionId();\n\t\tTaskExecution taskExecution = new TaskExecution(taskExecutionId, null, taskName, startTime, null, null,\n\t\t\t\targuments, null, externalExecutionId, parentExecutionId);\n\t\tthis.taskExecutions.put(taskExecutionId, taskExecution);\n\t\treturn taskExecution;\n\t}\n\n\t@Override\n\tpublic TaskExecution startTaskExecution(long executionId, String taskName, LocalDateTime startTime,\n\t\t\tList<String> arguments, String externalExecutionid) {\n\t\treturn startTaskExecution(executionId, taskName, startTime, arguments, externalExecutionid, null);\n\t}\n\n\t@Override\n\tpublic TaskExecution startTaskExecution(long executionId, String taskName, LocalDateTime startTime,\n\t\t\tList<String> arguments, String externalExecutionid, Long parentExecutionId) {\n\t\tTaskExecution taskExecution = this.taskExecutions.get(executionId);\n\t\ttaskExecution.setTaskName(taskName);\n\t\ttaskExecution.setStartTime(startTime);\n\t\ttaskExecution.setArguments(arguments);\n\t\ttaskExecution.setParentExecutionId(parentExecutionId);\n\t\tif (externalExecutionid != null) {\n\t\t\ttaskExecution.setExternalExecutionId(externalExecutionid);\n\t\t}\n\t\treturn taskExecution;\n\t}\n\n\t@Override\n\tpublic void completeTaskExecution(long executionId, Integer exitCode, LocalDateTime endTime, String exitMessage,\n\t\t\tString errorMessage) {\n\t\tif (!this.taskExecutions.containsKey(executionId)) {\n\t\t\tthrow new IllegalStateException(\"Invalid TaskExecution, ID \" + executionId + \" not found.\");\n\t\t}\n\n\t\tTaskExecution taskExecution = this.taskExecutions.get(executionId);\n\t\ttaskExecution.setEndTime(endTime);\n\t\ttaskExecution.setExitCode(exitCode);\n\t\ttaskExecution.setExitMessage(exitMessage);\n\t\ttaskExecution.setErrorMessage(errorMessage);\n\t}\n\n\t@Override\n\tpublic void completeTaskExecution(long executionId, Integer exitCode, LocalDateTime endTime, String exitMessage) {\n\t\tcompleteTaskExecution(executionId, exitCode, endTime, exitMessage, null);\n\t}\n\n\t@Override\n\tpublic TaskExecution getTaskExecution(long executionId) {\n\t\treturn this.taskExecutions.get(executionId);\n\t}\n\n\t@Override\n\tpublic long getTaskExecutionCountByTaskName(String taskName) {\n\t\tint count = 0;\n\t\tfor (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {\n\t\t\tif (entry.getValue().getTaskName().equals(taskName)) {\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\t@Override\n\tpublic long getTaskExecutionCountByExternalExecutionId(String externalExecutionId) {\n\t\tint count = 0;\n\t\tfor (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {\n\t\t\tif (entry.getValue().getExternalExecutionId().equals(externalExecutionId)) {\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\t@Override\n\tpublic long getRunningTaskExecutionCountByTaskName(String taskName) {\n\t\tint count = 0;\n\t\tfor (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {\n\t\t\tif (entry.getValue().getTaskName().equals(taskName) && entry.getValue().getEndTime() == null) {\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\t@Override\n\tpublic long getRunningTaskExecutionCount() {\n\t\tlong count = 0;\n\t\tfor (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {\n\t\t\tif (entry.getValue().getEndTime() == null) {\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\t@Override\n\tpublic long getTaskExecutionCount() {\n\t\treturn this.taskExecutions.size();\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findRunningTaskExecutions(String taskName, Pageable pageable) {\n\t\tSet<TaskExecution> result = getTaskExecutionTreeSet();\n\t\tfor (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {\n\t\t\tif (entry.getValue().getTaskName().equals(taskName) && entry.getValue().getEndTime() == null) {\n\t\t\t\tresult.add(entry.getValue());\n\t\t\t}\n\t\t}\n\t\treturn getPageFromList(new ArrayList<>(result), pageable, getRunningTaskExecutionCountByTaskName(taskName));\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findTaskExecutionsByExternalExecutionId(String externalExecutionId, Pageable pageable) {\n\t\tSet<TaskExecution> result = getTaskExecutionTreeSet();\n\t\tfor (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {\n\t\t\tif (entry.getValue().getExternalExecutionId().equals(externalExecutionId)) {\n\t\t\t\tresult.add(entry.getValue());\n\t\t\t}\n\t\t}\n\t\treturn getPageFromList(new ArrayList<>(result), pageable,\n\t\t\t\tgetTaskExecutionCountByExternalExecutionId(externalExecutionId));\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findTaskExecutionsByName(String taskName, Pageable pageable) {\n\t\tSet<TaskExecution> filteredSet = getTaskExecutionTreeSet();\n\t\tfor (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {\n\t\t\tif (entry.getValue().getTaskName().equals(taskName)) {\n\t\t\t\tfilteredSet.add(entry.getValue());\n\t\t\t}\n\t\t}\n\t\treturn getPageFromList(new ArrayList<>(filteredSet), pageable, getTaskExecutionCountByTaskName(taskName));\n\t}\n\n\t@Override\n\tpublic List<String> getTaskNames() {\n\t\tSet<String> result = new TreeSet<>();\n\t\tfor (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {\n\t\t\tresult.add(entry.getValue().getTaskName());\n\t\t}\n\t\treturn new ArrayList<>(result);\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findAll(Pageable pageable) {\n\t\tTreeSet<TaskExecution> sortedSet = getTaskExecutionTreeSet();\n\t\tsortedSet.addAll(this.taskExecutions.values());\n\t\tList<TaskExecution> result = new ArrayList<>(sortedSet.descendingSet());\n\t\treturn getPageFromList(result, pageable, getTaskExecutionCount());\n\t}\n\n\tpublic Map<Long, TaskExecution> getTaskExecutions() {\n\t\treturn Collections.unmodifiableMap(this.taskExecutions);\n\t}\n\n\tpublic long getNextExecutionId() {\n\t\treturn this.currentId.getAndIncrement();\n\t}\n\n\t@Override\n\tpublic Long getTaskExecutionIdByJobExecutionId(long jobExecutionId) {\n\t\tLong taskId = null;\n\n\t\tfound:\n\n\t\tfor (Map.Entry<Long, Set<Long>> association : this.batchJobAssociations.entrySet()) {\n\t\t\tfor (Long curJobExecutionId : association.getValue()) {\n\t\t\t\tif (curJobExecutionId.equals(jobExecutionId)) {\n\t\t\t\t\ttaskId = association.getKey();\n\t\t\t\t\tbreak found;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn taskId;\n\t}\n\n\t@Override\n\tpublic Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId) {\n\t\tif (this.batchJobAssociations.containsKey(taskExecutionId)) {\n\t\t\treturn Collections.unmodifiableSet(this.batchJobAssociations.get(taskExecutionId));\n\t\t}\n\t\telse {\n\t\t\treturn new TreeSet<>();\n\t\t}\n\t}\n\n\t@Override\n\tpublic void updateExternalExecutionId(long taskExecutionId, String externalExecutionId) {\n\t\tTaskExecution taskExecution = this.taskExecutions.get(taskExecutionId);\n\t\tAssert.notNull(taskExecution, \"Invalid TaskExecution, ID \" + taskExecutionId + \" not found.\");\n\t\ttaskExecution.setExternalExecutionId(externalExecutionId);\n\t}\n\n\tpublic ConcurrentMap<Long, Set<Long>> getBatchJobAssociations() {\n\t\treturn this.batchJobAssociations;\n\t}\n\n\tprivate TreeSet<TaskExecution> getTaskExecutionTreeSet() {\n\t\treturn new TreeSet<>(new Comparator<TaskExecution>() {\n\t\t\t@Override\n\t\t\tpublic int compare(TaskExecution e1, TaskExecution e2) {\n\t\t\t\tint result = e1.getStartTime().compareTo(e2.getStartTime());\n\t\t\t\tif (result == 0) {\n\t\t\t\t\tresult = Long.valueOf(e1.getExecutionId()).compareTo(e2.getExecutionId());\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate Page getPageFromList(List<TaskExecution> executionList, Pageable pageable, long maxSize) {\n\t\tlong toIndex = (pageable.getOffset() + pageable.getPageSize() > executionList.size()) ? executionList.size()\n\t\t\t\t: pageable.getOffset() + pageable.getPageSize();\n\t\treturn new PageImpl<>(executionList.subList((int) pageable.getOffset(), (int) toIndex), pageable, maxSize);\n\t}\n\n\t@Override\n\tpublic List<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames) {\n\n\t\tAssert.notEmpty(taskNames, \"At least 1 task name must be provided.\");\n\n\t\tfinal List<String> taskNamesAsList = new ArrayList<>();\n\n\t\tfor (String taskName : taskNames) {\n\t\t\tif (StringUtils.hasText(taskName)) {\n\t\t\t\ttaskNamesAsList.add(taskName);\n\t\t\t}\n\t\t}\n\n\t\tAssert.isTrue(taskNamesAsList.size() == taskNames.length,\n\t\t\t\tString.format(\"Task names must not contain any empty elements but %s of %s were empty or null.\",\n\t\t\t\t\t\ttaskNames.length - taskNamesAsList.size(), taskNames.length));\n\n\t\tfinal Map<String, TaskExecution> tempTaskExecutions = new HashMap<>();\n\n\t\tfor (Map.Entry<Long, TaskExecution> taskExecutionMapEntry : this.taskExecutions.entrySet()) {\n\t\t\tif (!taskNamesAsList.contains(taskExecutionMapEntry.getValue().getTaskName())) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfinal TaskExecution tempTaskExecution = tempTaskExecutions\n\t\t\t\t.get(taskExecutionMapEntry.getValue().getTaskName());\n\t\t\tif (tempTaskExecution == null\n\t\t\t\t\t|| tempTaskExecution.getStartTime().isBefore(taskExecutionMapEntry.getValue().getStartTime())\n\t\t\t\t\t|| (tempTaskExecution.getStartTime().equals(taskExecutionMapEntry.getValue().getStartTime())\n\t\t\t\t\t\t\t&& tempTaskExecution.getExecutionId() < taskExecutionMapEntry.getValue()\n\t\t\t\t\t\t\t\t.getExecutionId())) {\n\t\t\t\ttempTaskExecutions.put(taskExecutionMapEntry.getValue().getTaskName(),\n\t\t\t\t\t\ttaskExecutionMapEntry.getValue());\n\t\t\t}\n\t\t}\n\t\tfinal List<TaskExecution> latestTaskExecutions = new ArrayList<>(tempTaskExecutions.values());\n\t\tCollections.sort(latestTaskExecutions, new TaskExecutionComparator());\n\t\treturn latestTaskExecutions;\n\t}\n\n\t@Override\n\tpublic TaskExecution getLatestTaskExecutionForTaskName(String taskName) {\n\t\tAssert.hasText(taskName, \"The task name must not be empty.\");\n\t\tfinal List<TaskExecution> taskExecutions = this.getLatestTaskExecutionsByTaskNames(taskName);\n\t\tif (taskExecutions.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\t\telse if (taskExecutions.size() == 1) {\n\t\t\treturn taskExecutions.get(0);\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\"Only expected a single TaskExecution but received \" + taskExecutions.size());\n\t\t}\n\t}\n\n\tprivate static final class TaskExecutionComparator implements Comparator<TaskExecution>, Serializable {\n\n\t\t@Override\n\t\tpublic int compare(TaskExecution firstTaskExecution, TaskExecution secondTaskExecution) {\n\t\t\tif (firstTaskExecution.getStartTime().equals(secondTaskExecution.getStartTime())) {\n\t\t\t\treturn Long.compare(firstTaskExecution.getExecutionId(), secondTaskExecution.getExecutionId());\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn secondTaskExecution.getStartTime().compareTo(firstTaskExecution.getStartTime());\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/TaskExecutionDao.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.dao;\n\nimport java.time.LocalDateTime;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\n\n/**\n * Data Access Object for task executions.\n *\n * @author Glenn Renfro\n * @author Gunnar Hillert\n * @author David Turanski\n *\n */\npublic interface TaskExecutionDao {\n\n\t/**\n\t * Save a new {@link TaskExecution}.\n\t * @param taskName the name that associated with the task execution.\n\t * @param startTime the time task began.\n\t * @param arguments list of key/value pairs that configure the task.\n\t * @param externalExecutionId id assigned to the task by the platform\n\t * @return A fully qualified {@link TaskExecution} instance.\n\t */\n\tTaskExecution createTaskExecution(String taskName, LocalDateTime startTime, List<String> arguments,\n\t\t\tString externalExecutionId);\n\n\t/**\n\t * Save a new {@link TaskExecution}.\n\t * @param taskName the name that associated with the task execution.\n\t * @param startTime the time task began.\n\t * @param arguments list of key/value pairs that configure the task.\n\t * @param externalExecutionId id assigned to the task by the platform\n\t * @param parentExecutionId the parent task execution id.\n\t * @return A fully qualified {@link TaskExecution} instance.\n\t * @since 1.2.0\n\t */\n\tTaskExecution createTaskExecution(String taskName, LocalDateTime startTime, List<String> arguments,\n\t\t\tString externalExecutionId, Long parentExecutionId);\n\n\t/**\n\t * Update and existing {@link TaskExecution} to mark it as started.\n\t * @param executionId the id of the taskExecution to be updated.\n\t * @param taskName the name that associated with the task execution.\n\t * @param startTime the time task began.\n\t * @param arguments list of key/value pairs that configure the task.\n\t * @param externalExecutionId id assigned to the task by the platform\n\t * @return A TaskExecution containing the information available at task execution\n\t * start.\n\t * @since 1.1.0\n\t */\n\tTaskExecution startTaskExecution(long executionId, String taskName, LocalDateTime startTime, List<String> arguments,\n\t\t\tString externalExecutionId);\n\n\t/**\n\t * Update and existing {@link TaskExecution} to mark it as started.\n\t * @param executionId the id of the taskExecution to be updated.\n\t * @param taskName the name that associated with the task execution.\n\t * @param startTime the time task began.\n\t * @param arguments list of key/value pairs that configure the task.\n\t * @param externalExecutionId id assigned to the task by the platform\n\t * @param parentExecutionId the parent task execution id.\n\t * @return A TaskExecution containing the information available at task execution\n\t * start.\n\t * @since 1.2.0\n\t */\n\tTaskExecution startTaskExecution(long executionId, String taskName, LocalDateTime startTime, List<String> arguments,\n\t\t\tString externalExecutionId, Long parentExecutionId);\n\n\t/**\n\t * Update and existing {@link TaskExecution} to mark it as completed.\n\t * @param executionId the id of the taskExecution to be updated.\n\t * @param exitCode the status of the task upon completion.\n\t * @param endTime the time the task completed.\n\t * @param exitMessage the message assigned to the task upon completion.\n\t * @param errorMessage error information available upon failure of a task.\n\t * @since 1.1.0\n\t */\n\tvoid completeTaskExecution(long executionId, Integer exitCode, LocalDateTime endTime, String exitMessage,\n\t\t\tString errorMessage);\n\n\t/**\n\t * Update and existing {@link TaskExecution}.\n\t * @param executionId the id of the taskExecution to be updated.\n\t * @param exitCode the status of the task upon completion.\n\t * @param endTime the time the task completed.\n\t * @param exitMessage the message assigned to the task upon completion.\n\t */\n\tvoid completeTaskExecution(long executionId, Integer exitCode, LocalDateTime endTime, String exitMessage);\n\n\t/**\n\t * Retrieves a task execution from the task repository.\n\t * @param executionId the id associated with the task execution.\n\t * @return a fully qualified TaskExecution instance.\n\t */\n\tTaskExecution getTaskExecution(long executionId);\n\n\t/**\n\t * Retrieves current number of task executions for a taskName.\n\t * @param taskName the name of the task to search for in the repository.\n\t * @return current number of task executions for the taskName.\n\t */\n\tlong getTaskExecutionCountByTaskName(String taskName);\n\n\t/**\n\t * Retrieves current number of task executions for a taskName and with an endTime of\n\t * null.\n\t * @param taskName the name of the task to search for in the repository.\n\t * @return current number of task executions for the taskName.\n\t */\n\tlong getRunningTaskExecutionCountByTaskName(String taskName);\n\n\t/**\n\t * Retrieves current number of task executions with an endTime of null.\n\t * @return current number of task executions.\n\t */\n\tlong getRunningTaskExecutionCount();\n\n\t/**\n\t * Retrieves current number of task executions.\n\t * @return current number of task executions.\n\t */\n\tlong getTaskExecutionCount();\n\n\t/**\n\t * Retrieves a set of task executions that are running for a taskName.\n\t * @param taskName the name of the task to search for in the repository.\n\t * @param pageable the constraints for the search.\n\t * @return set of running task executions.\n\t */\n\tPage<TaskExecution> findRunningTaskExecutions(String taskName, Pageable pageable);\n\n\t/**\n\t * Retrieve a collection of taskExecutions that contain the provided external\n\t * execution id.\n\t * @param externalExecutionId the external execution id of the tasks\n\t * @param pageable the constraints for the search\n\t * @return the set of task executions for tasks with the externalExecutionId\n\t */\n\tPage<TaskExecution> findTaskExecutionsByExternalExecutionId(String externalExecutionId, Pageable pageable);\n\n\t/**\n\t * Retrieves current number of task executions for a externalTaskExecutionId.\n\t * @param externalExecutionId the external execution id of the task to search for in\n\t * the repository.\n\t * @return current number of task executions for the externalExecutionId.\n\t */\n\n\tlong getTaskExecutionCountByExternalExecutionId(String externalExecutionId);\n\n\t/**\n\t * Retrieves a subset of task executions by task name, start location and size.\n\t * @param taskName the name of the task to search for in the repository.\n\t * @param pageable the constraints for the search.\n\t * @return a list that contains task executions from the query bound by the start\n\t * position and count specified by the user.\n\t */\n\tPage<TaskExecution> findTaskExecutionsByName(String taskName, Pageable pageable);\n\n\t/**\n\t * Retrieves a sorted list of distinct task names for the task executions.\n\t * @return a list of distinct task names from the task repository..\n\t */\n\tList<String> getTaskNames();\n\n\t/**\n\t * Retrieves all the task executions within the pageable constraints.\n\t * @param pageable the constraints for the search\n\t * @return page containing the results from the search\n\t */\n\n\tPage<TaskExecution> findAll(Pageable pageable);\n\n\t/**\n\t * Retrieves the next available execution id for a task execution.\n\t * @return long containing the executionId.\n\t */\n\tlong getNextExecutionId();\n\n\t/**\n\t * Returns the id of the TaskExecution that the requested Spring Batch job execution\n\t * was executed within the context of. Returns null if non were found.\n\t * @param jobExecutionId the id of the JobExecution\n\t * @return the id of the {@link TaskExecution}\n\t */\n\tLong getTaskExecutionIdByJobExecutionId(long jobExecutionId);\n\n\t/**\n\t * Returns the job execution ids associated with a task execution id.\n\t * @param taskExecutionId id of the {@link TaskExecution}\n\t * @return a <code>Set</code> of the ids of the job executions executed within the\n\t * task.\n\t */\n\tSet<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId);\n\n\t/**\n\t * Updates the externalExecutionId for the execution id specified.\n\t * @param taskExecutionId the execution id for the task to be updated.\n\t * @param externalExecutionId the new externalExecutionId.\n\t */\n\tvoid updateExternalExecutionId(long taskExecutionId, String externalExecutionId);\n\n\t/**\n\t * Returns a {@link List} of the latest {@link TaskExecution} for 1 or more task\n\t * names.\n\t *\n\t * Latest is defined by the most recent start time. A {@link TaskExecution} does not\n\t * have to be finished (The results may including pending {@link TaskExecution}s).\n\t *\n\t * It is theoretically possible that a {@link TaskExecution} with the same name to\n\t * have more than 1 {@link TaskExecution} for the exact same start time. In that case\n\t * the {@link TaskExecution} with the highest Task Execution ID is returned.\n\t *\n\t * This method will not consider end times in its calculations. Thus, when a task\n\t * execution {@code A} starts after task execution {@code B} but finishes BEFORE task\n\t * execution {@code A}, then task execution {@code B} is being returned.\n\t * @param taskNames At least 1 task name must be provided\n\t * @return List of TaskExecutions. May be empty but never null.\n\t */\n\tList<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames);\n\n\t/**\n\t * Returns the latest task execution for a given task name. Will ultimately apply the\n\t * same algorithm underneath as {@link #getLatestTaskExecutionsByTaskNames(String...)}\n\t * but will only return a single result.\n\t * @param taskName Must not be null or empty\n\t * @return The latest Task Execution or null\n\t * @see #getLatestTaskExecutionsByTaskNames(String...)\n\t */\n\tTaskExecution getLatestTaskExecutionForTaskName(String taskName);\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/dao/package-info.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Interface DAO and default implementations for storing and retrieving data for tasks\n * from a repository.\n */\npackage org.springframework.cloud.task.repository.dao;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/PagingQueryProvider.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database;\n\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.batch.infrastructure.item.database.Order;\nimport org.springframework.data.domain.Pageable;\n\n/**\n * Interface defining the functionality to be provided for generating paging queries.\n *\n * @author Glenn Renfro\n */\npublic interface PagingQueryProvider {\n\n\t/**\n\t * Initialize the query provider using the provided {@link DataSource} if necessary.\n\t * @param dataSource DataSource to use for any initialization\n\t * @throws Exception throws {@link Exception} if query provider initialize fails.\n\t */\n\tvoid init(DataSource dataSource) throws Exception;\n\n\t/**\n\t * The number of parameters that are declared in the query.\n\t * @return number of parameters\n\t */\n\tint getParameterCount();\n\n\t/**\n\t * Indicate whether the generated queries use named parameter syntax.\n\t * @return true if named parameter syntax is used\n\t */\n\tboolean isUsingNamedParameters();\n\n\t/**\n\t * The sort keys. A Map of the columns that make up the key and a Boolean indicating\n\t * ascending or descending (ascending = true).\n\t * @return the sort keys used to order the query\n\t */\n\tMap<String, Order> getSortKeys();\n\n\t/**\n\t *\n\t * Generate the query that will provide the jump to item query.\n\t * @param pageable the coordinates to pull the next page from the datasource\n\t * @return the generated query\n\t */\n\tString getPageQuery(Pageable pageable);\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Database-specific components for Spring Cloud Task repository.\n */\npackage org.springframework.cloud.task.repository.database;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/AbstractSqlPagingQueryProvider.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.batch.infrastructure.item.database.JdbcParameterUtils;\nimport org.springframework.batch.infrastructure.item.database.Order;\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.dao.InvalidDataAccessApiUsageException;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * Abstract SQL Paging Query Provider to serve as a base class for all provided SQL paging\n * query providers.\n *\n * Any implementation must provide a way to specify the select clause, from clause and\n * optionally a where clause. It is recommended that there should be an index for the sort\n * key to provide better performance.\n *\n * Provides properties and preparation for the mandatory \"selectClause\" and \"fromClause\"\n * as well as for the optional \"whereClause\".\n *\n * @author Glenn Renfro\n */\npublic abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvider {\n\n\tprivate String selectClause;\n\n\tprivate String fromClause;\n\n\tprivate String whereClause;\n\n\tprivate Map<String, Order> sortKeys = new LinkedHashMap<>();\n\n\tprivate int parameterCount;\n\n\tprivate boolean usingNamedParameters;\n\n\t/**\n\t * @return SQL SELECT clause part of SQL query string\n\t */\n\tprotected String getSelectClause() {\n\t\treturn this.selectClause;\n\t}\n\n\t/**\n\t * @param selectClause SELECT clause part of SQL query string\n\t */\n\tpublic void setSelectClause(String selectClause) {\n\t\tthis.selectClause = removeKeyWord(\"select\", selectClause);\n\t}\n\n\t/**\n\t * @return SQL FROM clause part of SQL query string\n\t */\n\tprotected String getFromClause() {\n\t\treturn this.fromClause;\n\t}\n\n\t/**\n\t * @param fromClause FROM clause part of SQL query string\n\t */\n\tpublic void setFromClause(String fromClause) {\n\t\tthis.fromClause = removeKeyWord(\"from\", fromClause);\n\t}\n\n\t/**\n\t * @return SQL WHERE clause part of SQL query string\n\t */\n\tprotected String getWhereClause() {\n\t\treturn this.whereClause;\n\t}\n\n\t/**\n\t * @param whereClause WHERE clause part of SQL query string\n\t */\n\tpublic void setWhereClause(String whereClause) {\n\t\tif (StringUtils.hasText(whereClause)) {\n\t\t\tthis.whereClause = removeKeyWord(\"where\", whereClause);\n\t\t}\n\t\telse {\n\t\t\tthis.whereClause = null;\n\t\t}\n\t}\n\n\t/**\n\t * A Map&lt;String, Order&gt; of sort columns as the key and {@link Order} for\n\t * ascending/descending.\n\t * @return sortKey key to use to sort and limit page content\n\t */\n\t@Override\n\tpublic Map<String, Order> getSortKeys() {\n\t\treturn this.sortKeys;\n\t}\n\n\t/**\n\t * @param sortKeys key to use to sort and limit page content\n\t */\n\tpublic void setSortKeys(Map<String, Order> sortKeys) {\n\t\tthis.sortKeys = sortKeys;\n\t}\n\n\t@Override\n\tpublic int getParameterCount() {\n\t\treturn this.parameterCount;\n\t}\n\n\t@Override\n\tpublic boolean isUsingNamedParameters() {\n\t\treturn this.usingNamedParameters;\n\t}\n\n\t@Override\n\tpublic void init(DataSource dataSource) throws Exception {\n\t\tAssert.notNull(dataSource, \"DataSource must not be null\");\n\t\tAssert.hasLength(this.selectClause, \"selectClause must be specified\");\n\t\tAssert.hasLength(this.fromClause, \"fromClause must be specified\");\n\t\tAssert.notEmpty(this.sortKeys, \"sortKey must be specified\");\n\t\tStringBuilder sql = new StringBuilder();\n\t\tsql.append(\"SELECT \").append(this.selectClause);\n\t\tsql.append(\" FROM \").append(this.fromClause);\n\t\tif (this.whereClause != null) {\n\t\t\tsql.append(\" WHERE \").append(this.whereClause);\n\t\t}\n\t\tList<String> namedParameters = new ArrayList<>();\n\t\tthis.parameterCount = JdbcParameterUtils.countParameterPlaceholders(sql.toString(), namedParameters);\n\t\tif (namedParameters.size() > 0) {\n\t\t\tif (this.parameterCount != namedParameters.size()) {\n\t\t\t\tthrow new InvalidDataAccessApiUsageException(\n\t\t\t\t\t\t\"You can't use both named parameters and classic \\\"?\\\" placeholders: \" + sql);\n\t\t\t}\n\t\t\tthis.usingNamedParameters = true;\n\t\t}\n\t}\n\n\tprivate String removeKeyWord(String keyWord, String clause) {\n\t\tString temp = clause.trim();\n\t\tString keyWordString = keyWord + \" \";\n\t\tif (temp.toLowerCase(Locale.ROOT).startsWith(keyWordString) && temp.length() > keyWordString.length()) {\n\t\t\treturn temp.substring(keyWordString.length());\n\t\t}\n\t\telse {\n\t\t\treturn temp;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/Db2PagingQueryProvider.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport org.springframework.data.domain.Pageable;\n\n/**\n * IBM DB2 implementation of a\n * {@link org.springframework.cloud.task.repository.database.PagingQueryProvider} using\n * database specific features.\n *\n * @author Thomas Schuettel\n * @author Ryan DCruz\n */\npublic class Db2PagingQueryProvider extends AbstractSqlPagingQueryProvider {\n\n\t@Override\n\tpublic String getPageQuery(Pageable pageable) {\n\t\tlong offset = pageable.getOffset() + 1;\n\t\treturn generateRowNumSqlQueryWithNesting(getSelectClause(), false,\n\t\t\t\t\"TMP_ROW_NUM >= \" + offset + \" AND TMP_ROW_NUM < \" + (offset + pageable.getPageSize()));\n\t}\n\n\tprivate String generateRowNumSqlQueryWithNesting(String selectClause, boolean remainingPageQuery,\n\t\t\tString rowNumClause) {\n\t\tStringBuilder sql = new StringBuilder();\n\t\tsql.append(\"SELECT \")\n\t\t\t.append(selectClause)\n\t\t\t.append(\" FROM (SELECT \")\n\t\t\t.append(selectClause)\n\t\t\t.append(\", \")\n\t\t\t.append(\"ROW_NUMBER() OVER() as TMP_ROW_NUM\");\n\t\tsql.append(\" FROM (SELECT \").append(selectClause).append(\" FROM \").append(this.getFromClause());\n\t\tSqlPagingQueryUtils.buildWhereClause(this, remainingPageQuery, sql);\n\t\tsql.append(\" ORDER BY \").append(SqlPagingQueryUtils.buildSortClause(this));\n\t\tsql.append(\")) WHERE \").append(rowNumClause);\n\n\t\treturn sql.toString();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/H2PagingQueryProvider.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.data.domain.Pageable;\n\n/**\n * H2 implementation of a {@link PagingQueryProvider} using database specific features.\n *\n * @author Glenn Renfro\n * @author Henning Pöttker\n */\npublic class H2PagingQueryProvider extends AbstractSqlPagingQueryProvider {\n\n\t@Override\n\tpublic String getPageQuery(Pageable pageable) {\n\t\tString limitClause = new StringBuilder().append(\"OFFSET \")\n\t\t\t.append(pageable.getOffset())\n\t\t\t.append(\" ROWS FETCH NEXT \")\n\t\t\t.append(pageable.getPageSize())\n\t\t\t.append(\" ROWS ONLY\")\n\t\t\t.toString();\n\t\treturn SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/HsqlPagingQueryProvider.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.data.domain.Pageable;\n\n/**\n * HSQLDB implementation of a {@link PagingQueryProvider} using database specific\n * features.\n *\n * @author Glenn Renfro\n */\npublic class HsqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {\n\n\t@Override\n\tpublic String getPageQuery(Pageable pageable) {\n\t\tString topClause = new StringBuilder().append(\"LIMIT \")\n\t\t\t.append(pageable.getOffset())\n\t\t\t.append(\" \")\n\t\t\t.append(pageable.getPageSize())\n\t\t\t.toString();\n\t\treturn SqlPagingQueryUtils.generateTopJumpToQuery(this, topClause);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/MariaDbPagingQueryProvider.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.data.domain.Pageable;\n\n/**\n * MariaDB implementation of a {@link PagingQueryProvider} using database specific\n * features.\n *\n * @author Glenn Renfro\n */\npublic class MariaDbPagingQueryProvider extends AbstractSqlPagingQueryProvider {\n\n\t@Override\n\tpublic String getPageQuery(Pageable pageable) {\n\t\tString topClause = new StringBuilder().append(\"LIMIT \")\n\t\t\t.append(pageable.getOffset())\n\t\t\t.append(\", \")\n\t\t\t.append(pageable.getPageSize())\n\t\t\t.toString();\n\t\treturn SqlPagingQueryUtils.generateLimitJumpToQuery(this, topClause);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/MySqlPagingQueryProvider.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.data.domain.Pageable;\n\n/**\n * MySQL implementation of a {@link PagingQueryProvider} using database specific features.\n *\n * @author Glenn Renfro\n */\npublic class MySqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {\n\n\t@Override\n\tpublic String getPageQuery(Pageable pageable) {\n\t\tString topClause = new StringBuilder().append(\"LIMIT \")\n\t\t\t.append(pageable.getOffset())\n\t\t\t.append(\", \")\n\t\t\t.append(pageable.getPageSize())\n\t\t\t.toString();\n\t\treturn SqlPagingQueryUtils.generateLimitJumpToQuery(this, topClause);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/OraclePagingQueryProvider.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.data.domain.Pageable;\n\n/**\n * Oracle implementation of a {@link PagingQueryProvider} using database specific\n * features.\n *\n * @author Glenn Renfro\n */\npublic class OraclePagingQueryProvider extends AbstractSqlPagingQueryProvider {\n\n\t@Override\n\tpublic String getPageQuery(Pageable pageable) {\n\t\tlong offset = pageable.getOffset() + 1;\n\t\treturn generateRowNumSqlQueryWithNesting(getSelectClause(), false,\n\t\t\t\t\"TMP_ROW_NUM >= \" + offset + \" AND TMP_ROW_NUM < \" + (offset + pageable.getPageSize()));\n\t}\n\n\tprivate String generateRowNumSqlQueryWithNesting(String selectClause, boolean remainingPageQuery,\n\t\t\tString rowNumClause) {\n\t\tStringBuilder sql = new StringBuilder();\n\t\tsql.append(\"SELECT \")\n\t\t\t.append(selectClause)\n\t\t\t.append(\" FROM (SELECT \")\n\t\t\t.append(selectClause)\n\t\t\t.append(\", \")\n\t\t\t.append(\"ROWNUM as TMP_ROW_NUM\");\n\t\tsql.append(\" FROM (SELECT \").append(selectClause).append(\" FROM \").append(this.getFromClause());\n\t\tSqlPagingQueryUtils.buildWhereClause(this, remainingPageQuery, sql);\n\t\tsql.append(\" ORDER BY \").append(SqlPagingQueryUtils.buildSortClause(this));\n\t\tsql.append(\")) WHERE \").append(rowNumClause);\n\n\t\treturn sql.toString();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/PostgresPagingQueryProvider.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.data.domain.Pageable;\n\n/**\n * Postgres implementation of a {@link PagingQueryProvider} using database specific\n * features.\n *\n * @author Glenn Renfro\n */\npublic class PostgresPagingQueryProvider extends AbstractSqlPagingQueryProvider {\n\n\t@Override\n\tpublic String getPageQuery(Pageable pageable) {\n\t\tString limitClause = new StringBuilder().append(\"LIMIT \")\n\t\t\t.append(pageable.getPageSize())\n\t\t\t.append(\" OFFSET \")\n\t\t\t.append(pageable.getOffset())\n\t\t\t.toString();\n\t\treturn SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/SqlPagingQueryProviderFactoryBean.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.batch.infrastructure.item.database.Order;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.cloud.task.repository.support.DatabaseType;\nimport org.springframework.jdbc.support.MetaDataAccessException;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\nimport static org.springframework.cloud.task.repository.support.DatabaseType.DB2;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.DB2AS400;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.DB2VSE;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.DB2ZOS;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.H2;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.HSQL;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.MARIADB;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.MYSQL;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.ORACLE;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.POSTGRES;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.SQLSERVER;\n\n/**\n * Factory bean for {@link PagingQueryProvider} interface. The database type will be\n * determined from the data source if not provided explicitly. Valid types are given by\n * the {@link DatabaseType} enum.\n *\n * @author Glenn Renfro\n */\npublic class SqlPagingQueryProviderFactoryBean implements FactoryBean<PagingQueryProvider> {\n\n\tprivate DataSource dataSource;\n\n\tprivate String databaseType;\n\n\tprivate String fromClause;\n\n\tprivate String whereClause;\n\n\tprivate String selectClause;\n\n\tprivate Map<String, Order> sortKeys;\n\n\tprivate Map<DatabaseType, AbstractSqlPagingQueryProvider> providers = new HashMap<>();\n\n\t{\n\t\tthis.providers.put(HSQL, new HsqlPagingQueryProvider());\n\t\tthis.providers.put(H2, new H2PagingQueryProvider());\n\t\tthis.providers.put(MYSQL, new MySqlPagingQueryProvider());\n\t\tthis.providers.put(MARIADB, new MariaDbPagingQueryProvider());\n\t\tthis.providers.put(POSTGRES, new PostgresPagingQueryProvider());\n\t\tthis.providers.put(ORACLE, new OraclePagingQueryProvider());\n\t\tthis.providers.put(SQLSERVER, new SqlServerPagingQueryProvider());\n\t\tthis.providers.put(DB2, new Db2PagingQueryProvider());\n\t\tthis.providers.put(DB2VSE, new Db2PagingQueryProvider());\n\t\tthis.providers.put(DB2ZOS, new Db2PagingQueryProvider());\n\t\tthis.providers.put(DB2AS400, new Db2PagingQueryProvider());\n\t}\n\n\t/**\n\t * @param databaseType the databaseType to set\n\t */\n\tpublic void setDatabaseType(String databaseType) {\n\t\tAssert.hasText(databaseType, \"databaseType must not be empty nor null\");\n\t\tthis.databaseType = databaseType;\n\t}\n\n\t/**\n\t * @param dataSource the dataSource to set\n\t */\n\tpublic void setDataSource(DataSource dataSource) {\n\t\tAssert.notNull(dataSource, \"dataSource must not be null\");\n\t\tthis.dataSource = dataSource;\n\t}\n\n\t/**\n\t * @param fromClause the fromClause to set\n\t */\n\tpublic void setFromClause(String fromClause) {\n\t\tAssert.hasText(fromClause, \"fromClause must not be empty nor null\");\n\t\tthis.fromClause = fromClause;\n\t}\n\n\t/**\n\t * @param whereClause the whereClause to set\n\t */\n\tpublic void setWhereClause(String whereClause) {\n\t\tthis.whereClause = whereClause;\n\t}\n\n\t/**\n\t * @param selectClause the selectClause to set\n\t */\n\tpublic void setSelectClause(String selectClause) {\n\t\tAssert.hasText(selectClause, \"selectClause must not be empty nor null\");\n\t\tthis.selectClause = selectClause;\n\t}\n\n\t/**\n\t * @param sortKeys the sortKeys to set\n\t */\n\tpublic void setSortKeys(Map<String, Order> sortKeys) {\n\t\tthis.sortKeys = sortKeys;\n\t}\n\n\t/**\n\t * Get a {@link PagingQueryProvider} instance using the provided properties and\n\t * appropriate for the given database type.\n\t *\n\t * @see FactoryBean#getObject()\n\t */\n\t@Override\n\tpublic PagingQueryProvider getObject() throws Exception {\n\n\t\tDatabaseType type;\n\t\ttry {\n\t\t\ttype = this.databaseType != null ? DatabaseType.valueOf(this.databaseType.toUpperCase(Locale.ROOT))\n\t\t\t\t\t: DatabaseType.fromMetaData(this.dataSource);\n\t\t}\n\t\tcatch (MetaDataAccessException e) {\n\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\"Could not inspect meta data for database type.  You have to supply it explicitly.\", e);\n\t\t}\n\n\t\tAbstractSqlPagingQueryProvider provider = this.providers.get(type);\n\t\tAssert.state(provider != null, \"Should not happen: missing PagingQueryProvider for DatabaseType=\" + type);\n\n\t\tprovider.setFromClause(this.fromClause);\n\t\tprovider.setWhereClause(this.whereClause);\n\t\tprovider.setSortKeys(this.sortKeys);\n\t\tif (StringUtils.hasText(this.selectClause)) {\n\t\t\tprovider.setSelectClause(this.selectClause);\n\t\t}\n\t\tprovider.init(this.dataSource);\n\n\t\treturn provider;\n\n\t}\n\n\t/**\n\t * Always returns {@link PagingQueryProvider}.\n\t *\n\t * @see FactoryBean#getObjectType()\n\t */\n\t@Override\n\tpublic Class<PagingQueryProvider> getObjectType() {\n\t\treturn PagingQueryProvider.class;\n\t}\n\n\t/**\n\t * Always returns true.\n\t *\n\t * @see FactoryBean#isSingleton()\n\t */\n\t@Override\n\tpublic boolean isSingleton() {\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/SqlPagingQueryUtils.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport java.util.Map;\n\nimport org.springframework.batch.infrastructure.item.database.Order;\n\n/**\n * Utility class that generates the actual SQL statements used by query providers.\n *\n * @author Glenn Renfro\n */\npublic final class SqlPagingQueryUtils {\n\n\tprivate SqlPagingQueryUtils() {\n\t}\n\n\t/**\n\t * Generate SQL query string using a LIMIT clause.\n\t * @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation\n\t * specifics\n\t * @param limitClause the implementation specific top clause to be used\n\t * @return the generated query\n\t */\n\tpublic static String generateLimitJumpToQuery(AbstractSqlPagingQueryProvider provider, String limitClause) {\n\t\tStringBuilder sql = new StringBuilder();\n\t\tsql.append(\"SELECT \").append(provider.getSelectClause());\n\t\tsql.append(\" FROM \").append(provider.getFromClause());\n\t\tsql.append(provider.getWhereClause() == null ? \"\" : \" WHERE \" + provider.getWhereClause());\n\t\tsql.append(\" ORDER BY \").append(buildSortClause(provider));\n\t\tsql.append(\" \").append(limitClause);\n\n\t\treturn sql.toString();\n\t}\n\n\t/**\n\t * Generate SQL query string using a TOP clause.\n\t * @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation\n\t * specifics\n\t * @param topClause the implementation specific top clause to be used\n\t * @return the generated query\n\t */\n\tpublic static String generateTopJumpToQuery(AbstractSqlPagingQueryProvider provider, String topClause) {\n\t\tStringBuilder sql = new StringBuilder();\n\t\tsql.append(\"SELECT \").append(topClause).append(\" \").append(provider.getSelectClause());\n\t\tsql.append(\" FROM \").append(provider.getFromClause());\n\t\tsql.append(provider.getWhereClause() == null ? \"\" : \" WHERE \" + provider.getWhereClause());\n\t\tsql.append(\" ORDER BY \").append(buildSortClause(provider));\n\n\t\treturn sql.toString();\n\t}\n\n\t/**\n\t * Generates WHERE clause for queries that require sub selects.\n\t * @param provider the paging query provider that will provide the base where clause\n\t * @param remainingPageQuery if true assumes more will be appended to where clause\n\t * @param sql the sql statement to be appended.\n\t */\n\tpublic static void buildWhereClause(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery,\n\t\t\tStringBuilder sql) {\n\t\tif (remainingPageQuery) {\n\t\t\tsql.append(\" WHERE \");\n\t\t\tif (provider.getWhereClause() != null) {\n\t\t\t\tsql.append(\"(\");\n\t\t\t\tsql.append(provider.getWhereClause());\n\t\t\t\tsql.append(\") AND \");\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tsql.append(provider.getWhereClause() == null ? \"\" : \" WHERE \" + provider.getWhereClause());\n\t\t}\n\t}\n\n\t/**\n\t * Generates ORDER BY attributes based on the sort keys.\n\t * @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation\n\t * specifics\n\t * @return a String that can be appended to an ORDER BY clause.\n\t */\n\tpublic static String buildSortClause(AbstractSqlPagingQueryProvider provider) {\n\t\treturn buildSortClause(provider.getSortKeys());\n\t}\n\n\t/**\n\t * Generates ORDER BY attributes based on the sort keys.\n\t * @param sortKeys generates order by clause from map\n\t * @return a String that can be appended to an ORDER BY clause.\n\t */\n\tpublic static String buildSortClause(Map<String, Order> sortKeys) {\n\t\tStringBuilder builder = new StringBuilder();\n\t\tString prefix = \"\";\n\n\t\tfor (Map.Entry<String, Order> sortKey : sortKeys.entrySet()) {\n\t\t\tbuilder.append(prefix);\n\n\t\t\tprefix = \", \";\n\n\t\t\tbuilder.append(sortKey.getKey());\n\n\t\t\tif (sortKey.getValue() != null && sortKey.getValue() == Order.DESCENDING) {\n\t\t\t\tbuilder.append(\" DESC\");\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbuilder.append(\" ASC\");\n\t\t\t}\n\t\t}\n\n\t\treturn builder.toString();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/SqlServerPagingQueryProvider.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.data.domain.Pageable;\n\n/**\n * Sql Server implementation of a {@link PagingQueryProvider} using database specific\n * features.\n *\n * @author Glenn Renfro\n */\npublic class SqlServerPagingQueryProvider extends AbstractSqlPagingQueryProvider {\n\n\t@Override\n\tpublic String getPageQuery(Pageable pageable) {\n\t\tlong offset = pageable.getOffset() + 1;\n\t\treturn generateRowNumSqlQueryWithNesting(getSelectClause(), false,\n\t\t\t\t\"TMP_ROW_NUM >= \" + offset + \" AND TMP_ROW_NUM < \" + (offset + pageable.getPageSize()));\n\t}\n\n\tprivate String generateRowNumSqlQueryWithNesting(String selectClause, boolean remainingPageQuery,\n\t\t\tString rowNumClause) {\n\t\tStringBuilder sql = new StringBuilder();\n\t\tsql.append(\"SELECT \")\n\t\t\t.append(selectClause)\n\t\t\t.append(\" FROM (SELECT \")\n\t\t\t.append(selectClause)\n\t\t\t.append(\", \")\n\t\t\t.append(\"ROW_NUMBER() OVER (ORDER BY \")\n\t\t\t.append(SqlPagingQueryUtils.buildSortClause(this))\n\t\t\t.append(\") AS TMP_ROW_NUM \")\n\t\t\t.append(\" FROM \")\n\t\t\t.append(getFromClause());\n\t\tSqlPagingQueryUtils.buildWhereClause(this, remainingPageQuery, sql);\n\t\tsql.append(\") TASK_EXECUTION_PAGE \");\n\t\tsql.append(\" WHERE \").append(rowNumClause);\n\t\tsql.append(\" ORDER BY \").append(SqlPagingQueryUtils.buildSortClause(this));\n\t\treturn sql.toString();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes for database-specific Spring Cloud Task repository implementations.\n */\npackage org.springframework.cloud.task.repository.database.support;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Core repository interfaces and classes for Spring Cloud Task.\n */\npackage org.springframework.cloud.task.repository;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/DatabaseType.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport java.sql.DatabaseMetaData;\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.jdbc.support.DatabaseMetaDataCallback;\nimport org.springframework.jdbc.support.JdbcUtils;\nimport org.springframework.jdbc.support.MetaDataAccessException;\nimport org.springframework.util.StringUtils;\n\n/**\n * Enum representing a database type, such as DB2 or oracle. The type also contains a\n * product name, which is expected to be the same as the product name provided by the\n * database driver's metadata.\n *\n * @author Glenn Renfro\n */\npublic enum DatabaseType {\n\n\t/**\n\t * HSQL DB.\n\t */\n\tHSQL(\"HSQL Database Engine\"),\n\n\t/**\n\t * H2 DB.\n\t */\n\tH2(\"H2\"),\n\n\t/**\n\t * Oracle DB.\n\t */\n\tORACLE(\"Oracle\"),\n\n\t/**\n\t * MySQL DB.\n\t */\n\tMYSQL(\"MySQL\"),\n\n\t/**\n\t * MySQL DB.\n\t */\n\tMARIADB(\"MariaDB\"),\n\n\t/**\n\t * PostgreSQL DB.\n\t */\n\tPOSTGRES(\"PostgreSQL\"),\n\n\t/**\n\t * Microsoft SQL Server DB.\n\t */\n\tSQLSERVER(\"Microsoft SQL Server\"),\n\n\t/**\n\t * DB2 DB.\n\t */\n\tDB2(\"DB2\"),\n\n\t/**\n\t * DB2VSE DB.\n\t */\n\tDB2VSE(\"DB2VSE\"),\n\n\t/**\n\t * DB2ZOS DB.\n\t */\n\tDB2ZOS(\"DB2ZOS\"),\n\n\t/**\n\t * DB2AS400 DB.\n\t */\n\tDB2AS400(\"DB2AS400\");\n\n\tprivate static final Map<String, DatabaseType> dbNameMap;\n\n\tstatic {\n\t\tdbNameMap = new HashMap<>();\n\t\tfor (DatabaseType type : values()) {\n\t\t\tdbNameMap.put(type.getProductName(), type);\n\t\t}\n\t}\n\n\tprivate final String productName;\n\n\tDatabaseType(String productName) {\n\t\tthis.productName = productName;\n\t}\n\n\t/**\n\t * Convenience method that pulls a database product name from the DataSource's\n\t * metadata.\n\t * @param dataSource the datasource used to extact metadata.\n\t * @return DatabaseType The database type associated with the datasource.\n\t * @throws MetaDataAccessException thrown if failure occurs on metadata lookup.\n\t */\n\tpublic static DatabaseType fromMetaData(DataSource dataSource) throws SQLException, MetaDataAccessException {\n\t\tString databaseProductName = JdbcUtils.extractDatabaseMetaData(dataSource, new DatabaseMetaDataCallback() {\n\n\t\t\t@Override\n\t\t\tpublic Object processMetaData(DatabaseMetaData dbmd) throws SQLException, MetaDataAccessException {\n\t\t\t\treturn dbmd.getDatabaseProductName();\n\t\t\t}\n\t\t}).toString();\n\t\tif (StringUtils.hasText(databaseProductName) && !databaseProductName.equals(\"DB2/Linux\")\n\t\t\t\t&& databaseProductName.startsWith(\"DB2\")) {\n\t\t\tString databaseProductVersion = JdbcUtils\n\t\t\t\t.extractDatabaseMetaData(dataSource, new DatabaseMetaDataCallback() {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic Object processMetaData(DatabaseMetaData dbmd) throws SQLException, MetaDataAccessException {\n\t\t\t\t\t\treturn dbmd.getDatabaseProductVersion();\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.toString();\n\n\t\t\tif (databaseProductVersion.startsWith(\"ARI\")) {\n\t\t\t\tdatabaseProductName = \"DB2VSE\";\n\t\t\t}\n\t\t\telse if (databaseProductVersion.startsWith(\"DSN\")) {\n\t\t\t\tdatabaseProductName = \"DB2ZOS\";\n\t\t\t}\n\t\t\telse if (databaseProductName.indexOf(\"AS\") != -1 && (databaseProductVersion.startsWith(\"QSQ\")\n\t\t\t\t\t|| databaseProductVersion.substring(databaseProductVersion.indexOf('V'))\n\t\t\t\t\t\t.matches(\"V\\\\dR\\\\d[mM]\\\\d\"))) {\n\t\t\t\tdatabaseProductName = \"DB2AS400\";\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdatabaseProductName = JdbcUtils.commonDatabaseName(databaseProductName);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif (!databaseProductName.equals(MARIADB.getProductName())) {\n\t\t\t\tdatabaseProductName = JdbcUtils.commonDatabaseName(databaseProductName);\n\t\t\t}\n\t\t}\n\t\treturn fromProductName(databaseProductName);\n\t}\n\n\t/**\n\t * Static method to obtain a DatabaseType from the provided product name.\n\t * @param productName the name of the database.\n\t * @return DatabaseType for given product name.\n\t * @throws IllegalArgumentException if none is found.\n\t */\n\tpublic static DatabaseType fromProductName(String productName) {\n\t\tif (!dbNameMap.containsKey(productName)) {\n\t\t\tthrow new IllegalArgumentException(\"DatabaseType not found for product name: [\" + productName + \"]\");\n\t\t}\n\t\telse {\n\t\t\treturn dbNameMap.get(productName);\n\t\t}\n\t}\n\n\tprivate String getProductName() {\n\t\treturn this.productName;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskExplorer.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.dao.TaskExecutionDao;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.util.Assert;\n\n/**\n * TaskExplorer for that gathers task information from a task repository.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n * @author Gunnar Hillert\n * @author David Turanski\n */\npublic class SimpleTaskExplorer implements TaskExplorer {\n\n\tprivate TaskExecutionDao taskExecutionDao;\n\n\tpublic SimpleTaskExplorer(TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean) {\n\t\tAssert.notNull(taskExecutionDaoFactoryBean, \"taskExecutionDaoFactoryBean must not be null\");\n\n\t\ttry {\n\t\t\tthis.taskExecutionDao = taskExecutionDaoFactoryBean.getObject();\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tthrow new IllegalStateException(\"Unable to create a TaskExecutionDao\", e);\n\t\t}\n\t}\n\n\t@Override\n\tpublic TaskExecution getTaskExecution(long executionId) {\n\t\treturn this.taskExecutionDao.getTaskExecution(executionId);\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findRunningTaskExecutions(String taskName, Pageable pageable) {\n\t\treturn this.taskExecutionDao.findRunningTaskExecutions(taskName, pageable);\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findTaskExecutionsByExecutionId(String externalExecutionId, Pageable pageable) {\n\t\treturn this.taskExecutionDao.findTaskExecutionsByExternalExecutionId(externalExecutionId, pageable);\n\t}\n\n\t@Override\n\tpublic List<String> getTaskNames() {\n\t\treturn this.taskExecutionDao.getTaskNames();\n\t}\n\n\t@Override\n\tpublic long getTaskExecutionCountByTaskName(String taskName) {\n\t\treturn this.taskExecutionDao.getTaskExecutionCountByTaskName(taskName);\n\t}\n\n\t@Override\n\tpublic long getTaskExecutionCount() {\n\t\treturn this.taskExecutionDao.getTaskExecutionCount();\n\t}\n\n\t@Override\n\tpublic long getRunningTaskExecutionCount() {\n\t\treturn this.taskExecutionDao.getRunningTaskExecutionCount();\n\t}\n\n\t@Override\n\tpublic long getTaskExecutionCountByExternalExecutionId(String externalExecutionId) {\n\t\treturn this.taskExecutionDao.getTaskExecutionCountByExternalExecutionId(externalExecutionId);\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findTaskExecutionsByName(String taskName, Pageable pageable) {\n\t\treturn this.taskExecutionDao.findTaskExecutionsByName(taskName, pageable);\n\t}\n\n\t@Override\n\tpublic Page<TaskExecution> findAll(Pageable pageable) {\n\t\treturn this.taskExecutionDao.findAll(pageable);\n\t}\n\n\t@Override\n\tpublic Long getTaskExecutionIdByJobExecutionId(long jobExecutionId) {\n\t\treturn this.taskExecutionDao.getTaskExecutionIdByJobExecutionId(jobExecutionId);\n\t}\n\n\t@Override\n\tpublic Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId) {\n\t\treturn this.taskExecutionDao.getJobExecutionIdsByTaskExecutionId(taskExecutionId);\n\t}\n\n\t@Override\n\tpublic List<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames) {\n\t\treturn this.taskExecutionDao.getLatestTaskExecutionsByTaskNames(taskNames);\n\t}\n\n\t@Override\n\tpublic TaskExecution getLatestTaskExecutionForTaskName(String taskName) {\n\t\treturn this.taskExecutionDao.getLatestTaskExecutionForTaskName(taskName);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskNameResolver.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.cloud.task.repository.TaskNameResolver;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.util.StringUtils;\n\n/**\n * Simple implementation of the {@link TaskNameResolver} interface. Names the task based\n * on the following order of precedence:\n * <ol>\n * <li>A configured property <code>spring.cloud.task.name</code></li>\n * <li>The {@link ApplicationContext}'s id.</li>\n * </ol>\n *\n * @author Michael Minella\n * @see org.springframework.boot.context.ContextIdApplicationContextInitializer\n */\npublic class SimpleTaskNameResolver implements TaskNameResolver, ApplicationContextAware {\n\n\tprivate ApplicationContext context;\n\n\tprivate String configuredName;\n\n\t@Value(\"${spring.cloud.task.name:}\")\n\tpublic void setConfiguredName(String configuredName) {\n\t\tthis.configuredName = configuredName;\n\t}\n\n\t@Override\n\tpublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n\t\tthis.context = applicationContext;\n\t}\n\n\t@Override\n\tpublic String getTaskName() {\n\t\tif (StringUtils.hasText(this.configuredName)) {\n\t\t\treturn this.configuredName;\n\t\t}\n\t\telse {\n\t\t\treturn this.context.getId().replace(\":\", \"_\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskRepository.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport java.time.LocalDateTime;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.repository.dao.TaskExecutionDao;\nimport org.springframework.util.Assert;\n\n/**\n * Records the task execution information to the log and to TaskExecutionDao provided.\n *\n * @author Glenn Renfro\n */\npublic class SimpleTaskRepository implements TaskRepository {\n\n\t/**\n\t * Default max exit message size.\n\t */\n\tpublic static final int MAX_EXIT_MESSAGE_SIZE = 2500;\n\n\t/**\n\t * Default max task name size.\n\t */\n\tpublic static final int MAX_TASK_NAME_SIZE = 100;\n\n\t/**\n\t * Default max error message size.\n\t */\n\tpublic static final int MAX_ERROR_MESSAGE_SIZE = 2500;\n\n\tprivate static final Log logger = LogFactory.getLog(SimpleTaskRepository.class);\n\n\tprivate TaskExecutionDao taskExecutionDao;\n\n\tprivate FactoryBean<TaskExecutionDao> taskExecutionDaoFactoryBean;\n\n\tprivate boolean initialized = false;\n\n\tprivate int maxExitMessageSize = MAX_EXIT_MESSAGE_SIZE;\n\n\tprivate int maxTaskNameSize = MAX_TASK_NAME_SIZE;\n\n\tprivate int maxErrorMessageSize = MAX_ERROR_MESSAGE_SIZE;\n\n\tpublic SimpleTaskRepository(FactoryBean<TaskExecutionDao> taskExecutionDaoFactoryBean) {\n\t\tAssert.notNull(taskExecutionDaoFactoryBean, \"A FactoryBean that provides a TaskExecutionDao is required\");\n\n\t\tthis.taskExecutionDaoFactoryBean = taskExecutionDaoFactoryBean;\n\t}\n\n\tpublic SimpleTaskRepository(FactoryBean<TaskExecutionDao> taskExecutionDaoFactoryBean, Integer maxExitMessageSize,\n\t\t\tInteger maxTaskNameSize, Integer maxErrorMessageSize) {\n\t\tAssert.notNull(taskExecutionDaoFactoryBean, \"A FactoryBean that provides a TaskExecutionDao is required\");\n\t\tif (maxTaskNameSize != null) {\n\t\t\tthis.maxTaskNameSize = maxTaskNameSize;\n\t\t}\n\t\tif (maxExitMessageSize != null) {\n\t\t\tthis.maxExitMessageSize = maxExitMessageSize;\n\t\t}\n\t\tif (maxErrorMessageSize != null) {\n\t\t\tthis.maxErrorMessageSize = maxErrorMessageSize;\n\t\t}\n\t\tthis.taskExecutionDaoFactoryBean = taskExecutionDaoFactoryBean;\n\t}\n\n\t@Override\n\tpublic TaskExecution completeTaskExecution(long executionId, Integer exitCode, LocalDateTime endTime,\n\t\t\tString exitMessage) {\n\t\treturn completeTaskExecution(executionId, exitCode, endTime, exitMessage, null);\n\t}\n\n\t@Override\n\tpublic TaskExecution completeTaskExecution(long executionId, Integer exitCode, LocalDateTime endTime,\n\t\t\tString exitMessage, String errorMessage) {\n\t\tinitialize();\n\n\t\tvalidateCompletedTaskExitInformation(executionId, exitCode, endTime);\n\t\texitMessage = trimMessage(exitMessage, this.maxExitMessageSize);\n\t\terrorMessage = trimMessage(errorMessage, this.maxErrorMessageSize);\n\t\tthis.taskExecutionDao.completeTaskExecution(executionId, exitCode, endTime, exitMessage, errorMessage);\n\t\tlogger.debug(\"Updating: TaskExecution with executionId=\" + executionId + \" with the following {\" + \"exitCode=\"\n\t\t\t\t+ exitCode + \", endTime=\" + endTime + \", exitMessage='\" + exitMessage + '\\'' + \", errorMessage='\"\n\t\t\t\t+ errorMessage + '\\'' + '}');\n\n\t\treturn this.taskExecutionDao.getTaskExecution(executionId);\n\t}\n\n\t@Override\n\tpublic TaskExecution createTaskExecution(TaskExecution taskExecution) {\n\t\tinitialize();\n\t\tvalidateCreateInformation(taskExecution);\n\t\tTaskExecution daoTaskExecution = this.taskExecutionDao.createTaskExecution(taskExecution.getTaskName(),\n\t\t\t\ttaskExecution.getStartTime(), taskExecution.getArguments(), taskExecution.getExternalExecutionId(),\n\t\t\t\ttaskExecution.getParentExecutionId());\n\t\tlogger.debug(\"Creating: \" + taskExecution.toString());\n\t\treturn daoTaskExecution;\n\t}\n\n\t@Override\n\tpublic TaskExecution createTaskExecution(String name) {\n\t\tinitialize();\n\t\tTaskExecution taskExecution = this.taskExecutionDao.createTaskExecution(name, null,\n\t\t\t\tCollections.<String>emptyList(), null);\n\t\tlogger.debug(\"Creating: \" + taskExecution.toString());\n\t\treturn taskExecution;\n\t}\n\n\t@Override\n\tpublic TaskExecution createTaskExecution() {\n\t\treturn createTaskExecution((String) null);\n\t}\n\n\t@Override\n\tpublic TaskExecution startTaskExecution(long executionid, String taskName, LocalDateTime startTime,\n\t\t\tList<String> arguments, String externalExecutionId) {\n\t\treturn startTaskExecution(executionid, taskName, startTime, arguments, externalExecutionId, null);\n\t}\n\n\t@Override\n\tpublic void updateExternalExecutionId(long executionid, String externalExecutionId) {\n\t\tinitialize();\n\t\tthis.taskExecutionDao.updateExternalExecutionId(executionid, externalExecutionId);\n\t}\n\n\t@Override\n\tpublic TaskExecution startTaskExecution(long executionid, String taskName, LocalDateTime startTime,\n\t\t\tList<String> arguments, String externalExecutionId, Long parentExecutionId) {\n\t\tinitialize();\n\t\tTaskExecution taskExecution = this.taskExecutionDao.startTaskExecution(executionid, taskName, startTime,\n\t\t\t\targuments, externalExecutionId, parentExecutionId);\n\t\tlogger.debug(\"Starting: \" + taskExecution.toString());\n\t\treturn taskExecution;\n\t}\n\n\t/**\n\t * Retrieves the taskExecutionDao associated with this repository.\n\t * @return the taskExecutionDao\n\t */\n\tpublic TaskExecutionDao getTaskExecutionDao() {\n\t\tinitialize();\n\t\treturn this.taskExecutionDao;\n\t}\n\n\tprivate void initialize() {\n\t\tif (!this.initialized) {\n\t\t\ttry {\n\t\t\t\tthis.taskExecutionDao = this.taskExecutionDaoFactoryBean.getObject();\n\t\t\t\tthis.initialized = true;\n\t\t\t}\n\t\t\tcatch (Exception e) {\n\t\t\t\tthrow new IllegalStateException(\"Unable to create the TaskExecutionDao\", e);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Validate startTime and taskName are valid.\n\t * @param taskExecution task execution to validate\n\t */\n\tprivate void validateCreateInformation(TaskExecution taskExecution) {\n\t\tAssert.notNull(taskExecution.getStartTime(), \"TaskExecution start time cannot be null.\");\n\n\t\tif (taskExecution.getTaskName() != null && taskExecution.getTaskName().length() > this.maxTaskNameSize) {\n\t\t\tthrow new IllegalArgumentException(\"TaskName length exceeds \" + this.maxTaskNameSize + \" characters\");\n\t\t}\n\t}\n\n\tprivate void validateCompletedTaskExitInformation(long executionId, Integer exitCode, LocalDateTime endTime) {\n\t\tAssert.notNull(exitCode, \"exitCode should not be null\");\n\t\tAssert.isTrue(exitCode >= 0, \"exit code must be greater than or equal to zero\");\n\t\tAssert.notNull(endTime, \"TaskExecution endTime cannot be null.\");\n\t}\n\n\tprivate String trimMessage(String exitMessage, int maxSize) {\n\t\tString result = exitMessage;\n\t\tif (exitMessage != null && exitMessage.length() > maxSize) {\n\t\t\tresult = exitMessage.substring(0, maxSize);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic void setMaxExitMessageSize(int maxExitMessageSize) {\n\t\tthis.maxExitMessageSize = maxExitMessageSize;\n\t}\n\n\tpublic void setMaxTaskNameSize(int maxTaskNameSize) {\n\t\tthis.maxTaskNameSize = maxTaskNameSize;\n\t}\n\n\tpublic void setMaxErrorMessageSize(int maxErrorMessageSize) {\n\t\tthis.maxErrorMessageSize = maxErrorMessageSize;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/TaskExecutionDaoFactoryBean.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport java.sql.DatabaseMetaData;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.batch.infrastructure.item.database.support.DataFieldMaxValueIncrementerFactory;\nimport org.springframework.batch.infrastructure.item.database.support.DefaultDataFieldMaxValueIncrementerFactory;\nimport org.springframework.beans.factory.FactoryBean;\nimport org.springframework.cloud.task.configuration.TaskProperties;\nimport org.springframework.cloud.task.listener.TaskException;\nimport org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao;\nimport org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;\nimport org.springframework.cloud.task.repository.dao.TaskExecutionDao;\nimport org.springframework.jdbc.support.MetaDataAccessException;\nimport org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;\nimport org.springframework.jdbc.support.incrementer.SqlServerSequenceMaxValueIncrementer;\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/**\n * A {@link FactoryBean} implementation that creates the appropriate\n * {@link TaskExecutionDao} based on the provided information.\n *\n * @author Michael Minella\n * @author Glenn Renfro\n */\npublic class TaskExecutionDaoFactoryBean implements FactoryBean<TaskExecutionDao> {\n\n\tprivate DataSource dataSource;\n\n\tprivate TaskExecutionDao dao = null;\n\n\tprivate String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX;\n\n\t/**\n\t * Default constructor will result in a Map based TaskExecutionDao. <b>This is only\n\t * intended for testing purposes.</b>\n\t */\n\tpublic TaskExecutionDaoFactoryBean() {\n\t}\n\n\t/**\n\t * {@link DataSource} to be used.\n\t * @param dataSource {@link DataSource} to be used.\n\t * @param tablePrefix the table prefix to use for this dao.\n\t */\n\tpublic TaskExecutionDaoFactoryBean(DataSource dataSource, String tablePrefix) {\n\t\tthis(dataSource);\n\t\tAssert.hasText(tablePrefix, \"tablePrefix must not be null nor empty\");\n\t\tthis.tablePrefix = tablePrefix;\n\t}\n\n\t/**\n\t * {@link DataSource} to be used.\n\t * @param dataSource {@link DataSource} to be used.\n\t */\n\tpublic TaskExecutionDaoFactoryBean(DataSource dataSource) {\n\t\tAssert.notNull(dataSource, \"A DataSource is required\");\n\n\t\tthis.dataSource = dataSource;\n\t}\n\n\t@Override\n\tpublic TaskExecutionDao getObject() throws Exception {\n\t\tif (this.dao == null) {\n\t\t\tif (this.dataSource != null) {\n\t\t\t\tbuildTaskExecutionDao(this.dataSource);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.dao = new MapTaskExecutionDao();\n\t\t\t}\n\t\t}\n\t\tif (this.dataSource != null) {\n\t\t\tString databaseType = null;\n\t\t\ttry {\n\t\t\t\tdatabaseType = DatabaseType.fromMetaData(dataSource).name();\n\t\t\t}\n\t\t\tcatch (MetaDataAccessException e) {\n\t\t\t\tthrow new IllegalStateException(e);\n\t\t\t}\n\t\t\tif (StringUtils.hasText(databaseType) && databaseType.equals(\"SQLSERVER\")) {\n\t\t\t\tString incrementerName = this.tablePrefix + \"SEQ\";\n\t\t\t\tDataFieldMaxValueIncrementerFactory incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(\n\t\t\t\t\t\tdataSource);\n\t\t\t\tDataFieldMaxValueIncrementer incrementer = incrementerFactory.getIncrementer(databaseType,\n\t\t\t\t\t\tincrementerName);\n\t\t\t\tif (!isSqlServerTableSequenceAvailable(incrementerName)) {\n\t\t\t\t\tincrementer = new SqlServerSequenceMaxValueIncrementer(dataSource, this.tablePrefix + \"SEQ\");\n\t\t\t\t}\n\t\t\t\t((JdbcTaskExecutionDao) this.dao).setTaskIncrementer(incrementer);\n\t\t\t}\n\t\t}\n\t\treturn this.dao;\n\t}\n\n\t@Override\n\tpublic Class<?> getObjectType() {\n\t\treturn TaskExecutionDao.class;\n\t}\n\n\t@Override\n\tpublic boolean isSingleton() {\n\t\treturn true;\n\t}\n\n\tprivate void buildTaskExecutionDao(DataSource dataSource) {\n\t\tDataFieldMaxValueIncrementerFactory incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(\n\t\t\t\tdataSource);\n\t\tthis.dao = new JdbcTaskExecutionDao(dataSource, this.tablePrefix);\n\t\tString databaseType;\n\t\ttry {\n\t\t\tdatabaseType = DatabaseType.fromMetaData(dataSource).name();\n\t\t}\n\t\tcatch (MetaDataAccessException e) {\n\t\t\tthrow new IllegalStateException(e);\n\t\t}\n\t\tcatch (SQLException e) {\n\t\t\tthrow new IllegalStateException(e);\n\t\t}\n\t\t((JdbcTaskExecutionDao) this.dao)\n\t\t\t.setTaskIncrementer(incrementerFactory.getIncrementer(databaseType, this.tablePrefix + \"SEQ\"));\n\t}\n\n\tprivate boolean isSqlServerTableSequenceAvailable(String incrementerName) {\n\t\tboolean result = false;\n\t\tDatabaseMetaData metaData = null;\n\t\ttry {\n\t\t\tmetaData = dataSource.getConnection().getMetaData();\n\t\t\tString[] types = { \"TABLE\" };\n\t\t\tResultSet tables = metaData.getTables(null, null, \"%\", types);\n\t\t\twhile (tables.next()) {\n\t\t\t\tif (tables.getString(\"TABLE_NAME\").equals(incrementerName)) {\n\t\t\t\t\tresult = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch (SQLException sqe) {\n\t\t\tthrow new TaskException(sqe.getMessage());\n\t\t}\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/TaskRepositoryInitializer.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport java.sql.SQLException;\nimport java.util.Locale;\n\nimport javax.sql.DataSource;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.cloud.task.configuration.TaskProperties;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\nimport org.springframework.jdbc.support.JdbcUtils;\nimport org.springframework.jdbc.support.MetaDataAccessException;\n\n/**\n * Utility for initializing the Task Repository's datasource. If a single\n * {@link DataSource} is available in the current context, and functionality is enabled\n * (as it is by default), this will initialize the database. If more than one DataSource\n * is available in the current context, custom configuration of this is required (if\n * desired).\n *\n * Initialization of the database can be disabled by configuring the property\n * <code>spring.cloud.task.initialize-enabled</code> to false.\n * <code>spring.cloud.task.initialize.enable</code> has been deprecated.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n */\n\npublic final class TaskRepositoryInitializer implements InitializingBean {\n\n\tprivate static final Log logger = LogFactory.getLog(TaskRepositoryInitializer.class);\n\n\tprivate static final String DEFAULT_SCHEMA_LOCATION = \"classpath:org/springframework/\"\n\t\t\t+ \"cloud/task/schema-@@platform@@.sql\";\n\n\t/**\n\t * Path to the SQL file to use to initialize the database schema.\n\t */\n\tprivate static String schema = DEFAULT_SCHEMA_LOCATION;\n\n\tprivate DataSource dataSource;\n\n\tprivate ResourceLoader resourceLoader;\n\n\t@Value(\"${spring.cloud.task.initialize.enable:true}\")\n\tprivate boolean taskInitializationEnabled;\n\n\tprivate TaskProperties taskProperties;\n\n\tpublic TaskRepositoryInitializer(TaskProperties taskProperties) {\n\t\tthis.taskProperties = taskProperties;\n\t}\n\n\tpublic void setDataSource(DataSource dataSource) {\n\t\tthis.dataSource = dataSource;\n\t}\n\n\t@Autowired(required = false)\n\tpublic void setResourceLoader(ResourceLoader resourceLoader) {\n\t\tthis.resourceLoader = resourceLoader;\n\t}\n\n\tprivate String getDatabaseType(DataSource dataSource) {\n\t\ttry {\n\t\t\treturn JdbcUtils.commonDatabaseName(DatabaseType.fromMetaData(dataSource).toString())\n\t\t\t\t.toLowerCase(Locale.ROOT);\n\t\t}\n\t\tcatch (MetaDataAccessException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to detect database type\", ex);\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to detect database type\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tboolean isInitializeEnabled = (this.taskProperties.isInitializeEnabled() != null)\n\t\t\t\t? this.taskProperties.isInitializeEnabled() : this.taskInitializationEnabled;\n\t\tif (this.dataSource != null && isInitializeEnabled\n\t\t\t\t&& this.taskProperties.getTablePrefix().equals(TaskProperties.DEFAULT_TABLE_PREFIX)) {\n\t\t\tString platform = getDatabaseType(this.dataSource);\n\t\t\tif (\"hsql\".equals(platform)) {\n\t\t\t\tplatform = \"hsqldb\";\n\t\t\t}\n\t\t\tif (\"postgres\".equals(platform)) {\n\t\t\t\tplatform = \"postgresql\";\n\t\t\t}\n\t\t\tif (\"oracle\".equals(platform)) {\n\t\t\t\tplatform = \"oracle\";\n\t\t\t}\n\t\t\tif (\"mysql\".equals(platform)) {\n\t\t\t\tplatform = \"mysql\";\n\t\t\t}\n\t\t\tif (\"sqlserver\".equals(platform)) {\n\t\t\t\tplatform = \"sqlserver\";\n\t\t\t}\n\t\t\tResourceDatabasePopulator populator = new ResourceDatabasePopulator();\n\t\t\tString schemaLocation = schema;\n\t\t\tschemaLocation = schemaLocation.replace(\"@@platform@@\", platform);\n\t\t\tpopulator.addScript(this.resourceLoader.getResource(schemaLocation));\n\t\t\tpopulator.setContinueOnError(true);\n\t\t\tlogger.debug(String.format(\"Initializing task schema for %s database\", platform));\n\t\t\tDatabasePopulatorUtils.execute(populator, this.dataSource);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/package-info.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Classes used for setting up and supporting a task repositories.\n */\npackage org.springframework.cloud.task.repository.support;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n\t\"properties\": [\n\t\t{\n\t\t\t\"defaultValue\": false,\n\t\t\t\"name\": \"spring.cloud.task.single-instance-enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task will execute if another task with the same app name is running.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t},{\n\t\t\t\"defaultValue\": \"springCloudTaskTransactionManager\",\n\t\t\t\"name\": \"spring.cloud.task.transaction-manager\",\n\t\t\t\"description\": \"This property is used to specify the transaction manager for TaskRepository. By default, a dedicated transaction manager is created by spring.\",\n\t\t\t\"type\": \"java.lang.String\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/META-INF/spring/aot.factories",
    "content": "org.springframework.aot.hint.RuntimeHintsRegistrar=\\\norg.springframework.cloud.task.configuration.TaskRuntimeHints\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.cloud.task.configuration.SingleTaskConfiguration\norg.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration\norg.springframework.cloud.task.configuration.observation.ObservationTaskAutoConfiguration\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/META-INF/spring.factories",
    "content": "org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector=\\\norg.springframework.cloud.task.configuration.TaskRepositoryDatabaseInitializerDetector\n\norg.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector=\\\norg.springframework.cloud.task.configuration.TaskRepositoryDependsOnDatabaseInitializationDetector\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.1.x/migration-h2.sql",
    "content": "/* If migrating from 1.1.0.M1 to 1.1.0.RELEASE you do not need to add\nthe ERROR_MESSAGE column. */\nalter table TASK_EXECUTION add ERROR_MESSAGE VARCHAR(2500);\nalter table TASK_EXECUTION add EXTERNAL_EXECUTION_ID VARCHAR(255);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.1.x/migration-hsqldb.sql",
    "content": "/* If migrating from 1.1.0.M1 to 1.1.0.RELEASE you do not need to add\nthe ERROR_MESSAGE column. */\nalter table TASK_EXECUTION add ERROR_MESSAGE VARCHAR(2500);\nalter table TASK_EXECUTION add EXTERNAL_EXECUTION_ID VARCHAR(255);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.1.x/migration-mysql.sql",
    "content": "/* If migrating from 1.1.0.M1 to 1.1.0.RELEASE you do not need to add\nthe ERROR_MESSAGE column. */\nalter table TASK_EXECUTION add ERROR_MESSAGE VARCHAR(2500);\nalter table TASK_EXECUTION add EXTERNAL_EXECUTION_ID VARCHAR(255);\n\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.1.x/migration-oracle.sql",
    "content": "/* If migrating from 1.1.0.M1 to 1.1.0.RELEASE you do not need to add\nthe ERROR_MESSAGE column. */\nalter table TASK_EXECUTION add ERROR_MESSAGE varchar2(2500);\nalter table TASK_EXECUTION add EXTERNAL_EXECUTION_ID varchar2(255);\n\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.1.x/migration-postgresql.sql",
    "content": "/* If migrating from 1.1.0.M1 to 1.1.0.RELEASE you do not need to add\nthe ERROR_MESSAGE column. */\nalter table TASK_EXECUTION add ERROR_MESSAGE VARCHAR(2500);\nalter table TASK_EXECUTION add EXTERNAL_EXECUTION_ID VARCHAR(255);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.1.x/migration-sqlserver.sql",
    "content": "/* If migrating from 1.1.0.M1 to 1.1.0.RELEASE you do not need to add\nthe ERROR_MESSAGE column. */\nalter table TASK_EXECUTION add ERROR_MESSAGE VARCHAR(2500);\nalter table TASK_EXECUTION add EXTERNAL_EXECUTION_ID VARCHAR(255);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.2.x/migration-db2.sql",
    "content": "alter table TASK_EXECUTION add PARENT_EXECUTION_ID BIGINT;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.2.x/migration-h2.sql",
    "content": "alter table TASK_EXECUTION add PARENT_EXECUTION_ID BIGINT;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.2.x/migration-hsqldb.sql",
    "content": "alter table TASK_EXECUTION add PARENT_EXECUTION_ID BIGINT;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.2.x/migration-mysql.sql",
    "content": "alter table TASK_EXECUTION add PARENT_EXECUTION_ID BIGINT;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.2.x/migration-oracle.sql",
    "content": "alter table TASK_EXECUTION add PARENT_EXECUTION_ID NUMBER;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.2.x/migration-postgresql.sql",
    "content": "alter table TASK_EXECUTION add PARENT_EXECUTION_ID BIGINT;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/1.2.x/migration-sqlserver.sql",
    "content": "alter table TASK_EXECUTION add PARENT_EXECUTION_ID BIGINT;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/2.2.x/migration-oracle.sql",
    "content": "alter table TASK_LOCK MODIFY LOCK_KEY VARCHAR2(36);\nalter table TASK_LOCK MODIFY CLIENT_ID VARCHAR2(36);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/3.0.x/migration-db2.sql",
    "content": "ALTER TABLE TASK_EXECUTION ALTER COLUMN START_TIME SET DATA TYPE TIMESTAMP(9);\nALTER TABLE TASK_EXECUTION ALTER COLUMN END_TIME SET DATA TYPE TIMESTAMP(9);\nALTER TABLE TASK_EXECUTION ALTER COLUMN LAST_UPDATED SET DATA TYPE TIMESTAMP(9);\nALTER TABLE TASK_LOCK ALTER COLUMN CREATED_DATE SET DATA TYPE TIMESTAMP(9);\n\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/3.0.x/migration-h2.sql",
    "content": "ALTER TABLE TASK_EXECUTION ALTER COLUMN START_TIME SET DATA TYPE TIMESTAMP(9);\nALTER TABLE TASK_EXECUTION ALTER COLUMN END_TIME SET DATA TYPE TIMESTAMP(9);\nALTER TABLE TASK_EXECUTION ALTER COLUMN LAST_UPDATED SET DATA TYPE TIMESTAMP(9);\nALTER TABLE TASK_LOCK ALTER COLUMN CREATED_DATE SET DATA TYPE TIMESTAMP(9);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/3.0.x/migration-hsqldb.sql",
    "content": "ALTER TABLE TASK_EXECUTION ALTER COLUMN START_TIME SET DATA TYPE TIMESTAMP(9);\nALTER TABLE TASK_EXECUTION ALTER COLUMN END_TIME SET DATA TYPE TIMESTAMP(9);\nALTER TABLE TASK_EXECUTION ALTER COLUMN LAST_UPDATED SET DATA TYPE TIMESTAMP(9);\nALTER TABLE TASK_LOCK ALTER COLUMN CREATED_DATE SET DATA TYPE TIMESTAMP(9);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/3.0.x/migration-mysql.sql",
    "content": "ALTER TABLE TASK_EXECUTION MODIFY COLUMN END_TIME DATETIME(6) NULL;\nALTER TABLE TASK_EXECUTION MODIFY COLUMN START_TIME DATETIME(6) NULL;\nALTER TABLE TASK_EXECUTION MODIFY COLUMN LAST_UPDATED DATETIME(6) NULL;\nALTER TABLE TASK_LOCK MODIFY COLUMN CREATED_DATE DATETIME(6) NULL;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/migration/3.0.x/migration-oracle.sql",
    "content": "ALTER TABLE TASK_EXECUTION MODIFY COLUMN CREATE_TIME TIMESTAMP(9);\nALTER TABLE TASK_EXECUTION MODIFY COLUMN START_TIME TIMESTAMP(9);\nALTER TABLE TASK_EXECUTION MODIFY COLUMN LAST_UPDATED TIMESTAMP(9);\nALTER TABLE TASK_LOCK MODIFY COLUMN CREATED_DATE TIMESTAMP(9);\n\n\nALTER SEQUENCE TASK_SEQ ORDER;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-db2.sql",
    "content": "\nCREATE TABLE TASK_EXECUTION  (\n\tTASK_EXECUTION_ID BIGINT  NOT NULL PRIMARY KEY ,\n\tSTART_TIME TIMESTAMP(9) DEFAULT NULL ,\n\tEND_TIME TIMESTAMP(9) DEFAULT NULL ,\n\tTASK_NAME  VARCHAR(100) ,\n\tEXIT_CODE INTEGER ,\n\tEXIT_MESSAGE VARCHAR(2500) ,\n\tERROR_MESSAGE VARCHAR(2500) ,\n\tLAST_UPDATED TIMESTAMP(9),\n\tEXTERNAL_EXECUTION_ID VARCHAR(255),\n\tPARENT_EXECUTION_ID BIGINT\n);\n\nCREATE TABLE TASK_EXECUTION_PARAMS  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL ,\n\tTASK_PARAM VARCHAR(2500) ,\n\tconstraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE TABLE TASK_TASK_BATCH (\n  TASK_EXECUTION_ID BIGINT NOT NULL ,\n  JOB_EXECUTION_ID BIGINT NOT NULL ,\n\tconstraint TASK_EXEC_BATCH_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE SEQUENCE TASK_SEQ AS BIGINT START WITH 0 MINVALUE 0 MAXVALUE 9223372036854775807 NOCACHE NOCYCLE;\n\nCREATE TABLE TASK_LOCK  (\n\tLOCK_KEY CHAR(36) NOT NULL,\n\tREGION VARCHAR(100) NOT NULL,\n\tCLIENT_ID CHAR(36),\n\tCREATED_DATE TIMESTAMP(9) NOT NULL,\n\tEXPIRED_AFTER TIMESTAMP(9) NOT NULL,\n\tconstraint LOCK_PK primary key (LOCK_KEY, REGION)\n);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-h2.sql",
    "content": "\nCREATE TABLE TASK_EXECUTION  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,\n\tSTART_TIME TIMESTAMP(9) DEFAULT NULL ,\n\tEND_TIME TIMESTAMP(9) DEFAULT NULL ,\n\tTASK_NAME  VARCHAR(100) ,\n\tEXIT_CODE INTEGER ,\n\tEXIT_MESSAGE VARCHAR(2500) ,\n\tERROR_MESSAGE VARCHAR(2500) ,\n\tLAST_UPDATED TIMESTAMP(9),\n\tEXTERNAL_EXECUTION_ID VARCHAR(255),\n\tPARENT_EXECUTION_ID BIGINT\n);\n\nCREATE TABLE TASK_EXECUTION_PARAMS  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL ,\n\tTASK_PARAM VARCHAR(2500) ,\n\tconstraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE TABLE TASK_TASK_BATCH (\n  TASK_EXECUTION_ID BIGINT NOT NULL ,\n  JOB_EXECUTION_ID BIGINT NOT NULL ,\n\tconstraint TASK_EXEC_BATCH_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE SEQUENCE TASK_SEQ ;\n\nCREATE TABLE TASK_LOCK  (\n\tLOCK_KEY CHAR(36) NOT NULL,\n\tREGION VARCHAR(100) NOT NULL,\n\tCLIENT_ID CHAR(36),\n\tCREATED_DATE TIMESTAMP(9) NOT NULL,\n\tEXPIRED_AFTER TIMESTAMP(9) NOT NULL,\n\tconstraint LOCK_PK primary key (LOCK_KEY, REGION)\n);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-hsqldb.sql",
    "content": "\nCREATE TABLE TASK_EXECUTION  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,\n\tSTART_TIME TIMESTAMP(9) DEFAULT NULL ,\n\tEND_TIME TIMESTAMP(9) DEFAULT NULL ,\n\tTASK_NAME  VARCHAR(100) ,\n\tEXIT_CODE INTEGER ,\n\tEXIT_MESSAGE VARCHAR(2500) ,\n\tERROR_MESSAGE VARCHAR(2500) ,\n\tLAST_UPDATED TIMESTAMP(9),\n\tEXTERNAL_EXECUTION_ID VARCHAR(255),\n\tPARENT_EXECUTION_ID BIGINT\n);\n\nCREATE TABLE TASK_EXECUTION_PARAMS  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL ,\n\tTASK_PARAM VARCHAR(2500) ,\n\tconstraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE TABLE TASK_TASK_BATCH (\n  TASK_EXECUTION_ID BIGINT NOT NULL ,\n  JOB_EXECUTION_ID BIGINT NOT NULL ,\n\tconstraint TASK_EXEC_BATCH_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE TABLE TASK_SEQ (\n\tID BIGINT IDENTITY\n);\n\nCREATE TABLE TASK_LOCK  (\n\tLOCK_KEY CHAR(36) NOT NULL,\n\tREGION VARCHAR(100) NOT NULL,\n\tCLIENT_ID CHAR(36),\n\tCREATED_DATE TIMESTAMP(9) NOT NULL,\n\tEXPIRED_AFTER TIMESTAMP(9) NOT NULL,\n\tconstraint LOCK_PK primary key (LOCK_KEY, REGION)\n);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-mariadb.sql",
    "content": "\nCREATE TABLE TASK_EXECUTION  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,\n\tSTART_TIME DATETIME(6) DEFAULT NULL ,\n\tEND_TIME DATETIME(6) DEFAULT NULL ,\n\tTASK_NAME  VARCHAR(100) ,\n\tEXIT_CODE INTEGER ,\n\tEXIT_MESSAGE VARCHAR(2500) ,\n\tERROR_MESSAGE VARCHAR(2500) ,\n\tLAST_UPDATED TIMESTAMP,\n\tEXTERNAL_EXECUTION_ID VARCHAR(255),\n\tPARENT_EXECUTION_ID BIGINT\n) ENGINE=InnoDB;\n\nCREATE TABLE TASK_EXECUTION_PARAMS  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL ,\n\tTASK_PARAM VARCHAR(2500) ,\n\tconstraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ENGINE=InnoDB;\n\nCREATE TABLE TASK_TASK_BATCH (\n TASK_EXECUTION_ID BIGINT NOT NULL ,\n JOB_EXECUTION_ID BIGINT NOT NULL ,\n\tconstraint TASK_EXEC_BATCH_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n)  ENGINE=InnoDB;\n\nCREATE TABLE TASK_LOCK  (\n\tLOCK_KEY CHAR(36) NOT NULL,\n\tREGION VARCHAR(100) NOT NULL,\n\tCLIENT_ID CHAR(36),\n\tCREATED_DATE DATETIME(6) NOT NULL,\n\tEXPIRED_AFTER DATETIME(6) NOT NULL,\n\tconstraint LOCK_PK primary key (LOCK_KEY, REGION)\n) ENGINE=InnoDB;\n\nCREATE SEQUENCE TASK_SEQ START WITH 1 MINVALUE 1 MAXVALUE 9223372036854775806 INCREMENT BY 1 NOCACHE NOCYCLE ENGINE=InnoDB;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-mysql.sql",
    "content": "\nCREATE TABLE TASK_EXECUTION  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,\n\tSTART_TIME DATETIME(6) DEFAULT NULL ,\n\tEND_TIME DATETIME(6) DEFAULT NULL ,\n\tTASK_NAME  VARCHAR(100) ,\n\tEXIT_CODE INTEGER ,\n\tEXIT_MESSAGE VARCHAR(2500) ,\n\tERROR_MESSAGE VARCHAR(2500) ,\n\tLAST_UPDATED TIMESTAMP,\n\tEXTERNAL_EXECUTION_ID VARCHAR(255),\n\tPARENT_EXECUTION_ID BIGINT\n) ENGINE=InnoDB;\n\nCREATE TABLE TASK_EXECUTION_PARAMS  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL ,\n\tTASK_PARAM VARCHAR(2500) ,\n\tconstraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ENGINE=InnoDB;\n\nCREATE TABLE TASK_TASK_BATCH (\n TASK_EXECUTION_ID BIGINT NOT NULL ,\n JOB_EXECUTION_ID BIGINT NOT NULL ,\n\tconstraint TASK_EXEC_BATCH_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n)  ENGINE=InnoDB;\n\nCREATE TABLE TASK_SEQ (\n\tID BIGINT NOT NULL,\n\tUNIQUE_KEY CHAR(1) NOT NULL,\n\tconstraint UNIQUE_KEY_UN unique (UNIQUE_KEY)\n) ENGINE=InnoDB;\n\nINSERT INTO TASK_SEQ (ID, UNIQUE_KEY) select * from (select 0 as ID, '0' as UNIQUE_KEY) as tmp;\n\nCREATE TABLE TASK_LOCK  (\n\tLOCK_KEY CHAR(36) NOT NULL,\n\tREGION VARCHAR(100) NOT NULL,\n\tCLIENT_ID CHAR(36),\n\tCREATED_DATE DATETIME(6) NOT NULL,\n\tEXPIRED_AFTER DATETIME(6) NOT NULL,\n\tconstraint LOCK_PK primary key (LOCK_KEY, REGION)\n) ENGINE=InnoDB;\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-oracle.sql",
    "content": "\nCREATE TABLE TASK_EXECUTION  (\n\tTASK_EXECUTION_ID NUMBER NOT NULL PRIMARY KEY ,\n\tSTART_TIME TIMESTAMP(9) DEFAULT NULL ,\n\tEND_TIME TIMESTAMP(9) DEFAULT NULL ,\n\tTASK_NAME  VARCHAR2(100) ,\n\tEXIT_CODE INTEGER ,\n\tEXIT_MESSAGE VARCHAR2(2500) ,\n\tERROR_MESSAGE VARCHAR2(2500) ,\n\tLAST_UPDATED TIMESTAMP(9),\n\tEXTERNAL_EXECUTION_ID VARCHAR2(255),\n\tPARENT_EXECUTION_ID NUMBER\n);\n\nCREATE TABLE TASK_EXECUTION_PARAMS  (\n\tTASK_EXECUTION_ID NUMBER NOT NULL ,\n\tTASK_PARAM VARCHAR2(2500) ,\n\tconstraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE TABLE TASK_TASK_BATCH (\n  TASK_EXECUTION_ID NUMBER NOT NULL ,\n  JOB_EXECUTION_ID NUMBER NOT NULL ,\n\tconstraint TASK_EXEC_BATCH_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE SEQUENCE TASK_SEQ START WITH 0 MINVALUE 0 MAXVALUE 9223372036854775807 ORDER NOCYCLE;\n\nCREATE TABLE TASK_LOCK  (\n\tLOCK_KEY VARCHAR2(36) NOT NULL,\n\tREGION VARCHAR2(100) NOT NULL,\n\tCLIENT_ID VARCHAR2(36),\n\tCREATED_DATE TIMESTAMP(9) NOT NULL,\n\tEXPIRED_AFTER TIMESTAMP(9) NOT NULL,\n\tconstraint LOCK_PK primary key (LOCK_KEY, REGION)\n);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-postgresql.sql",
    "content": "\nCREATE TABLE TASK_EXECUTION  (\n\tTASK_EXECUTION_ID BIGINT  NOT NULL PRIMARY KEY ,\n\tSTART_TIME TIMESTAMP DEFAULT NULL ,\n\tEND_TIME TIMESTAMP DEFAULT NULL ,\n\tTASK_NAME  VARCHAR(100) ,\n\tEXIT_CODE INTEGER ,\n\tEXIT_MESSAGE VARCHAR(2500) ,\n\tERROR_MESSAGE VARCHAR(2500) ,\n\tLAST_UPDATED TIMESTAMP ,\n\tEXTERNAL_EXECUTION_ID VARCHAR(255),\n\tPARENT_EXECUTION_ID BIGINT\n);\n\nCREATE TABLE TASK_EXECUTION_PARAMS  (\n\tTASK_EXECUTION_ID BIGINT NOT NULL ,\n\tTASK_PARAM VARCHAR(2500) ,\n\tconstraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE TABLE TASK_TASK_BATCH (\n  TASK_EXECUTION_ID BIGINT NOT NULL ,\n  JOB_EXECUTION_ID BIGINT NOT NULL ,\n\tconstraint TASK_EXEC_BATCH_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE SEQUENCE TASK_SEQ MAXVALUE 9223372036854775807 NO CYCLE;\n\nCREATE TABLE TASK_LOCK  (\n\tLOCK_KEY CHAR(36) NOT NULL,\n\tREGION VARCHAR(100) NOT NULL,\n\tCLIENT_ID CHAR(36),\n\tCREATED_DATE TIMESTAMP NOT NULL,\n\tEXPIRED_AFTER TIMESTAMP NOT NULL,\n\tconstraint LOCK_PK primary key (LOCK_KEY, REGION)\n);\n"
  },
  {
    "path": "spring-cloud-task-core/src/main/resources/org/springframework/cloud/task/schema-sqlserver.sql",
    "content": "CREATE TABLE TASK_EXECUTION  (\n  TASK_EXECUTION_ID BIGINT  NOT NULL PRIMARY KEY ,\n  START_TIME DATETIME DEFAULT NULL ,\n  END_TIME DATETIME DEFAULT NULL ,\n  TASK_NAME  VARCHAR(100) ,\n  EXIT_CODE INTEGER ,\n  EXIT_MESSAGE VARCHAR(2500) ,\n  ERROR_MESSAGE VARCHAR(2500) ,\n  LAST_UPDATED DATETIME ,\n  EXTERNAL_EXECUTION_ID VARCHAR(255),\n  PARENT_EXECUTION_ID BIGINT\n);\n\nCREATE TABLE TASK_EXECUTION_PARAMS  (\n  TASK_EXECUTION_ID BIGINT NOT NULL ,\n  TASK_PARAM VARCHAR(2500) ,\n  constraint TASK_EXEC_PARAMS_FK foreign key (TASK_EXECUTION_ID)\n  references TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE TABLE TASK_TASK_BATCH (\n  TASK_EXECUTION_ID BIGINT NOT NULL ,\n  JOB_EXECUTION_ID BIGINT NOT NULL ,\n\tconstraint TASK_EXEC_BATCH_FK foreign key (TASK_EXECUTION_ID)\n\treferences TASK_EXECUTION(TASK_EXECUTION_ID)\n) ;\n\nCREATE SEQUENCE TASK_SEQ START WITH 0 MINVALUE 0 MAXVALUE 9223372036854775807 NO CACHE NO CYCLE;\n\nCREATE TABLE TASK_LOCK  (\n  LOCK_KEY CHAR(36) NOT NULL,\n  REGION VARCHAR(100) NOT NULL,\n  CLIENT_ID CHAR(36),\n  CREATED_DATE DATETIME NOT NULL,\n  EXPIRED_AFTER DATETIME NOT NULL,\n  constraint LOCK_PK primary key (LOCK_KEY, REGION)\n);\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.configuration.SingleInstanceTaskListener;\nimport org.springframework.cloud.task.configuration.SingleTaskConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Verifies that the beans created by the SimpleSingleTaskAutoConfigurationConfiguration\n * specifically that PassThruRegistry was selected.\n *\n * @author Glenn Renfro\n * @since 2.0.0\n */\npublic class SimpleSingleTaskAutoConfigurationTests {\n\n\t@Test\n\tpublic void testConfiguration() {\n\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.cloud.task.singleInstanceEnabled=true\");\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tSingleInstanceTaskListener singleInstanceTaskListener = context.getBean(SingleInstanceTaskListener.class);\n\n\t\t\tassertThat(singleInstanceTaskListener).as(\"singleInstanceTaskListener should not be null\").isNotNull();\n\n\t\t\tassertThat(SingleInstanceTaskListener.class).isEqualTo(singleInstanceTaskListener.getClass());\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationWithDataSourceTests.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.configuration.SingleInstanceTaskListener;\nimport org.springframework.cloud.task.configuration.SingleTaskConfiguration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Verifies that the beans created by the SimpleSingleTaskAutoConfigurationConfiguration\n * specifically that the JdbcLockRegistry was selected.\n *\n * @author Glenn Renfro\n * @since 2.0.0\n */\npublic class SimpleSingleTaskAutoConfigurationWithDataSourceTests {\n\n\t@Test\n\tpublic void testConfiguration() {\n\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(\n\t\t\t\t\tAutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, SimpleTaskAutoConfiguration.class,\n\t\t\t\t\t\t\tSingleTaskConfiguration.class, EmbeddedDataSourceConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.cloud.task.singleInstanceEnabled=true\");\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tSingleInstanceTaskListener singleInstanceTaskListener = context.getBean(SingleInstanceTaskListener.class);\n\n\t\t\tassertThat(singleInstanceTaskListener).as(\"singleInstanceTaskListener should not be null\").isNotNull();\n\n\t\t\tassertThat(SingleInstanceTaskListener.class).isEqualTo(singleInstanceTaskListener.getClass());\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskAutoConfigurationTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.function.Executable;\n\nimport org.springframework.aop.framework.AopProxyUtils;\nimport org.springframework.aop.scope.ScopedProxyUtils;\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.BeanDefinitionHolder;\nimport org.springframework.beans.factory.config.ConfigurableListableBeanFactory;\nimport org.springframework.beans.factory.support.BeanDefinitionRegistry;\nimport org.springframework.beans.factory.support.GenericBeanDefinition;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.configuration.DefaultTaskConfigurer;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.configuration.SingleTaskConfiguration;\nimport org.springframework.cloud.task.configuration.TaskConfigurer;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.TaskNameResolver;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.repository.support.SimpleTaskRepository;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Verifies that the beans created by the SimpleTaskAutoConfiguration.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n */\npublic class SimpleTaskAutoConfigurationTests {\n\n\t@Test\n\tpublic void testRepository() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class));\n\t\tapplicationContextRunner.run((context) -> {\n\n\t\t\tTaskRepository taskRepository = context.getBean(TaskRepository.class);\n\t\t\tassertThat(taskRepository).isNotNull();\n\t\t\tClass<?> targetClass = AopProxyUtils.ultimateTargetClass(taskRepository);\n\t\t\tassertThat(targetClass).isEqualTo(SimpleTaskRepository.class);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testAutoConfigurationDisabled() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))\n\t\t\t.withPropertyValues(\"spring.cloud.task.autoconfiguration.enabled=false\");\n\t\tExecutable executable = () -> {\n\t\t\tapplicationContextRunner.run((context) -> {\n\t\t\t\tcontext.getBean(TaskRepository.class);\n\t\t\t});\n\t\t};\n\t\tverifyExceptionThrown(\n\t\t\t\tNoSuchBeanDefinitionException.class, \"No qualifying \"\n\t\t\t\t\t\t+ \"bean of type 'org.springframework.cloud.task.repository.TaskRepository' \" + \"available\",\n\t\t\t\texecutable);\n\t}\n\n\t@Test\n\tpublic void testRepositoryInitialized() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class, SimpleTaskAutoConfiguration.class,\n\t\t\t\t\tSingleTaskConfiguration.class))\n\t\t\t.withUserConfiguration(TaskLifecycleListenerConfiguration.class);\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tTaskExplorer taskExplorer = context.getBean(TaskExplorer.class);\n\t\t\tassertThat(taskExplorer.getTaskExecutionCount()).isEqualTo(1L);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testRepositoryBeansDependOnTaskRepositoryInitializer() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class, SimpleTaskAutoConfiguration.class,\n\t\t\t\t\tSingleTaskConfiguration.class))\n\t\t\t.withUserConfiguration(TaskLifecycleListenerConfiguration.class);\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tConfigurableListableBeanFactory beanFactory = context.getBeanFactory();\n\t\t\tString[] taskRepositoryNames = beanFactory.getBeanNamesForType(TaskRepository.class);\n\t\t\tassertThat(taskRepositoryNames).isNotEmpty();\n\t\t\tfor (String taskRepositoryName : taskRepositoryNames) {\n\t\t\t\tassertThat(beanFactory.getBeanDefinition(taskRepositoryName).getDependsOn())\n\t\t\t\t\t.contains(\"taskRepositoryInitializer\");\n\t\t\t}\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testRepositoryNotInitialized() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class, SimpleTaskAutoConfiguration.class,\n\t\t\t\t\tSingleTaskConfiguration.class))\n\t\t\t.withUserConfiguration(TaskLifecycleListenerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cloud.task.tablePrefix=foobarless\");\n\n\t\tverifyExceptionThrownDefaultExecutable(ApplicationContextException.class, applicationContextRunner);\n\t}\n\n\t@Test\n\tpublic void testTaskNameResolver() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class, SimpleTaskAutoConfiguration.class,\n\t\t\t\t\tSingleTaskConfiguration.class))\n\t\t\t.withUserConfiguration(TaskLifecycleListenerConfiguration.class)\n\t\t\t.withPropertyValues(\"spring.cloud.task.name=myTestName\");\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tTaskNameResolver taskNameResolver = context.getBean(TaskNameResolver.class);\n\t\t\tassertThat(taskNameResolver.getTaskName()).isEqualTo(\"myTestName\");\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testMultipleConfigurers() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))\n\t\t\t.withUserConfiguration(MultipleConfigurers.class);\n\n\t\tverifyExceptionThrownDefaultExecutable(BeanCreationException.class, \"Error creating bean \"\n\t\t\t\t+ \"with name 'org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration': Invocation of init method failed\",\n\t\t\t\tapplicationContextRunner);\n\t}\n\n\t@Test\n\tpublic void testMultipleDataSources() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))\n\t\t\t.withUserConfiguration(MultipleDataSources.class);\n\n\t\tverifyExceptionThrownDefaultExecutable(BeanCreationException.class, \"Error creating bean \"\n\t\t\t\t+ \"with name 'org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration': Invocation of init method failed\",\n\t\t\t\tapplicationContextRunner);\n\n\t}\n\n\t@Test\n\tvoid testSpecifyTransactionManager() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))\n\t\t\t.withBean(\"transactionManager\", ResourcelessTransactionManager.class)\n\t\t\t.withPropertyValues(\"spring.cloud.task.transaction-manager=transactionManager\");\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tassertThat(context.getBeanNamesForType(PlatformTransactionManager.class)).hasSize(1)\n\t\t\t\t.contains(\"transactionManager\")\n\t\t\t\t.doesNotContain(\"springCloudTaskTransactionManager\");\n\t\t});\n\t}\n\n\t@Test\n\tvoid testDefaultTransactionManager() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class));\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tassertThat(context.getBeanNamesForType(PlatformTransactionManager.class)).hasSize(1)\n\t\t\t\t.contains(\"springCloudTaskTransactionManager\")\n\t\t\t\t.doesNotContain(\"transactionManager\");\n\t\t});\n\t}\n\n\tpublic void verifyExceptionThrownDefaultExecutable(Class classToCheck,\n\t\t\tApplicationContextRunner applicationContextRunner) {\n\t\tExecutable executable = () -> {\n\t\t\tapplicationContextRunner.run((context) -> {\n\t\t\t\tThrowable expectedException = context.getStartupFailure();\n\t\t\t\tassertThat(expectedException).isNotNull();\n\t\t\t\tthrow expectedException;\n\t\t\t});\n\t\t};\n\t\tassertThatExceptionOfType(classToCheck).isThrownBy(executable::execute);\n\t}\n\n\tpublic void verifyExceptionThrownDefaultExecutable(Class classToCheck, String message,\n\t\t\tApplicationContextRunner applicationContextRunner) {\n\t\tExecutable executable = () -> {\n\t\t\tapplicationContextRunner.run((context) -> {\n\t\t\t\tThrowable expectedException = context.getStartupFailure();\n\t\t\t\tassertThat(expectedException).isNotNull();\n\t\t\t\tthrow expectedException;\n\t\t\t});\n\t\t};\n\t\tverifyExceptionThrown(classToCheck, message, executable);\n\t}\n\n\tpublic void verifyExceptionThrown(Class classToCheck, String message, Executable executable) {\n\t\tassertThatExceptionOfType(classToCheck).isThrownBy(executable::execute).withMessage(message);\n\t}\n\n\t/**\n\t * Verify that the verifyEnvironment method skips DataSource Proxy Beans when\n\t * determining the number of available dataSources.\n\t */\n\t@Test\n\tpublic void testWithDataSourceProxy() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class,\n\t\t\t\t\tPropertyPlaceholderAutoConfiguration.class, SimpleTaskAutoConfiguration.class,\n\t\t\t\t\tSingleTaskConfiguration.class))\n\t\t\t.withUserConfiguration(DataSourceProxyConfiguration.class);\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tassertThat(context.getBeanNamesForType(DataSource.class).length).isEqualTo(2);\n\t\t\tSimpleTaskAutoConfiguration taskConfiguration = context.getBean(SimpleTaskAutoConfiguration.class);\n\t\t\tassertThat(taskConfiguration).isNotNull();\n\t\t\tassertThat(taskConfiguration.taskExplorer()).isNotNull();\n\t\t});\n\t}\n\n\t@Configuration\n\tpublic static class MultipleConfigurers {\n\n\t\t@Bean\n\t\tpublic TaskConfigurer taskConfigurer1() {\n\t\t\treturn new DefaultTaskConfigurer((DataSource) null);\n\t\t}\n\n\t\t@Bean\n\t\tpublic TaskConfigurer taskConfigurer2() {\n\t\t\treturn new DefaultTaskConfigurer((DataSource) null);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class MultipleDataSources {\n\n\t\t@Bean\n\t\tpublic DataSource dataSource() {\n\t\t\treturn mock(DataSource.class);\n\t\t}\n\n\t\t@Bean\n\t\tpublic DataSource dataSource2() {\n\t\t\treturn mock(DataSource.class);\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class DataSourceProxyConfiguration {\n\n\t\t@Autowired\n\t\tprivate ConfigurableApplicationContext context;\n\n\t\t@Bean\n\t\tpublic BeanDefinitionHolder proxyDataSource() {\n\t\t\tGenericBeanDefinition proxyBeanDefinition = new GenericBeanDefinition();\n\t\t\tproxyBeanDefinition.setBeanClassName(\"javax.sql.DataSource\");\n\t\t\tBeanDefinitionHolder myDataSource = new BeanDefinitionHolder(proxyBeanDefinition, \"dataSource2\");\n\t\t\tScopedProxyUtils.createScopedProxy(myDataSource, (BeanDefinitionRegistry) this.context.getBeanFactory(),\n\t\t\t\t\ttrue);\n\t\t\treturn myDataSource;\n\t\t}\n\n\t}\n\n\t@EnableTask\n\t@Configuration\n\tpublic static class TaskLifecycleListenerConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Verifies core behavior for Tasks.\n *\n * @author Glenn Renfro\n */\n@ExtendWith(OutputCaptureExtension.class)\npublic class TaskCoreTests {\n\n\tprivate static final String TASK_NAME = \"taskEventTest\";\n\n\tprivate static final String EXCEPTION_MESSAGE = \"FOO EXCEPTION\";\n\n\tprivate static final String CREATE_TASK_MESSAGE = \"Creating: TaskExecution{executionId=\";\n\n\tprivate static final String UPDATE_TASK_MESSAGE = \"Updating: TaskExecution with executionId=\";\n\n\tprivate static final String SUCCESS_EXIT_CODE_MESSAGE = \"with the following {exitCode=0\";\n\n\tprivate static final String EXCEPTION_EXIT_CODE_MESSAGE = \"with the following {exitCode=1\";\n\n\tprivate static final String EXCEPTION_INVALID_TASK_EXECUTION_ID = \"java.lang.IllegalArgumentException: \"\n\t\t\t+ \"Invalid TaskExecution, ID 55 not found\";\n\n\tprivate static final String ERROR_MESSAGE = \"errorMessage='java.lang.IllegalStateException: \" + \"FOO EXCEPTION\";\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\t@AfterEach\n\tpublic void teardown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void successfulTaskTest(CapturedOutput capturedOutput) {\n\t\tthis.applicationContext = SpringApplication.run(TaskConfiguration.class,\n\t\t\t\t\"--spring.cloud.task.closecontext.enable=false\", \"--spring.cloud.task.name=\" + TASK_NAME,\n\t\t\t\t\"--spring.main.web-environment=false\");\n\n\t\tString output = capturedOutput.toString();\n\t\tassertThat(output.contains(CREATE_TASK_MESSAGE)).as(\"Test results do not show create task message: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(UPDATE_TASK_MESSAGE)).as(\"Test results do not show success message: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(SUCCESS_EXIT_CODE_MESSAGE)).as(\"Test results have incorrect exit code: \" + output)\n\t\t\t.isTrue();\n\t}\n\n\t/**\n\t * Test to verify that deprecated annotation does not affect task execution.\n\t */\n\t@Test\n\tpublic void successfulTaskTestWithAnnotation(CapturedOutput capturedOutput) {\n\t\tthis.applicationContext = SpringApplication.run(TaskConfigurationWithAnotation.class,\n\t\t\t\t\"--spring.cloud.task.closecontext.enable=false\", \"--spring.cloud.task.name=\" + TASK_NAME,\n\t\t\t\t\"--spring.main.web-environment=false\");\n\n\t\tString output = capturedOutput.toString();\n\t\tassertThat(output.contains(CREATE_TASK_MESSAGE)).as(\"Test results do not show create task message: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(UPDATE_TASK_MESSAGE)).as(\"Test results do not show success message: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(SUCCESS_EXIT_CODE_MESSAGE)).as(\"Test results have incorrect exit code: \" + output)\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tpublic void exceptionTaskTest(CapturedOutput capturedOutput) {\n\t\tboolean exceptionFired = false;\n\t\ttry {\n\t\t\tthis.applicationContext = SpringApplication.run(TaskExceptionConfiguration.class,\n\t\t\t\t\t\"--spring.cloud.task.closecontext.enable=false\", \"--spring.cloud.task.name=\" + TASK_NAME,\n\t\t\t\t\t\"--spring.main.web-environment=false\");\n\t\t}\n\t\tcatch (IllegalStateException exception) {\n\t\t\texceptionFired = true;\n\t\t}\n\t\tassertThat(exceptionFired).as(\"An IllegalStateException should have been thrown\").isTrue();\n\n\t\tString output = capturedOutput.toString();\n\t\tassertThat(output.contains(CREATE_TASK_MESSAGE)).as(\"Test results do not show create task message: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(UPDATE_TASK_MESSAGE)).as(\"Test results do not show success message: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(EXCEPTION_EXIT_CODE_MESSAGE)).as(\"Test results have incorrect exit code: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(ERROR_MESSAGE)).as(\"Test results have incorrect exit message: \" + output).isTrue();\n\t\tassertThat(output.contains(EXCEPTION_MESSAGE)).as(\"Test results have exception message: \" + output).isTrue();\n\t}\n\n\t@Test\n\tpublic void invalidExecutionId(CapturedOutput capturedOutput) {\n\t\tboolean exceptionFired = false;\n\t\ttry {\n\t\t\tthis.applicationContext = SpringApplication.run(TaskExceptionConfiguration.class,\n\t\t\t\t\t\"--spring.cloud.task.closecontext.enable=false\", \"--spring.cloud.task.name=\" + TASK_NAME,\n\t\t\t\t\t\"--spring.main.web-environment=false\", \"--spring.cloud.task.executionid=55\");\n\t\t}\n\t\tcatch (ApplicationContextException exception) {\n\t\t\texceptionFired = true;\n\t\t}\n\t\tassertThat(exceptionFired).as(\"An ApplicationContextException should have been thrown\").isTrue();\n\n\t\tString output = capturedOutput.toString();\n\t\tassertThat(output.contains(EXCEPTION_INVALID_TASK_EXECUTION_ID))\n\t\t\t.as(\"Test results do not show the correct exception message: \" + output)\n\t\t\t.isTrue();\n\t}\n\n\t@EnableTask\n\t@ImportAutoConfiguration({ SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\tpublic static class TaskConfiguration {\n\n\t\t@Bean\n\t\tpublic CommandLineRunner commandLineRunner() {\n\t\t\treturn new CommandLineRunner() {\n\t\t\t\t@Override\n\t\t\t\tpublic void run(String... strings) throws Exception {\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@EnableTask\n\t@ImportAutoConfiguration({ SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\tpublic static class TaskConfigurationWithAnotation {\n\n\t\t@Bean\n\t\tpublic CommandLineRunner commandLineRunner() {\n\t\t\treturn new CommandLineRunner() {\n\t\t\t\t@Override\n\t\t\t\tpublic void run(String... strings) throws Exception {\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n\t@EnableTask\n\t@ImportAutoConfiguration({ SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class })\n\tpublic static class TaskExceptionConfiguration {\n\n\t\t@Bean\n\t\tpublic CommandLineRunner commandLineRunner() {\n\t\t\treturn new CommandLineRunner() {\n\t\t\t\t@Override\n\t\t\t\tpublic void run(String... strings) throws Exception {\n\t\t\t\t\tthrow new IllegalStateException(EXCEPTION_MESSAGE);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerDefaultTaskConfigurerTests.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.configuration.TaskConfigurer;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;\n\n/**\n * Verifies that TaskRepositoryInitializer creates tables if a {@link TaskConfigurer} has\n * a {@link DataSource}.\n *\n * @author Glenn Renfro\n * @since 2.0.0\n */\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = { SimpleTaskAutoConfiguration.class, EmbeddedDataSourceConfiguration.class })\n@DirtiesContext\npublic class TaskRepositoryInitializerDefaultTaskConfigurerTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tpublic void testTablesCreated() {\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource);\n\t\tList<Map<String, Object>> rows = jdbcTemplate.queryForList(\"SHOW TABLES\");\n\t\tassertThat(rows.size()).isEqualTo(4);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerNoDataSourceTaskConfigurerTests.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.cloud.task.configuration.DefaultTaskConfigurer;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.configuration.SingleTaskConfiguration;\nimport org.springframework.cloud.task.configuration.TaskConfigurer;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;\n\n/**\n * Verifies that TaskRepositoryInitializer does not create tables if a\n * {@link TaskConfigurer} has no {@link DataSource}.\n *\n * @author Glenn Renfro\n * @since 2.0.0\n */\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = { SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class,\n\t\tEmbeddedDataSourceConfiguration.class, DefaultTaskConfigurer.class })\npublic class TaskRepositoryInitializerNoDataSourceTaskConfigurerTests {\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\tpublic void testNoTablesCreated() {\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource);\n\t\tList<Map<String, Object>> rows = jdbcTemplate.queryForList(\"SHOW TABLES\");\n\t\tassertThat(rows.size()).isEqualTo(0);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/DefaultTaskConfigurerTests.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport javax.sql.DataSource;\n\nimport jakarta.persistence.EntityManager;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.cloud.task.repository.support.SimpleTaskRepository;\nimport org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\n\n/**\n * @author Glenn Renfro\n * @author Mahmoud Ben Hassine\n */\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = { EmbeddedDataSourceConfiguration.class })\npublic class DefaultTaskConfigurerTests {\n\n\t@Autowired\n\tDataSource dataSource;\n\n\t@Autowired\n\tApplicationContext context;\n\n\t@Test\n\tpublic void resourcelessTransactionManagerTest() {\n\t\tDefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer();\n\t\tassertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())\n\t\t\t.isEqualTo(\"org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(\"foo\");\n\t\tassertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())\n\t\t\t.isEqualTo(\"org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager\");\n\t}\n\n\t@Test\n\tpublic void testDefaultContext() {\n\t\tAnnotationConfigApplicationContext localContext = new AnnotationConfigApplicationContext();\n\t\tlocalContext.register(EmbeddedDataSourceConfiguration.class, EntityManagerConfiguration.class);\n\t\tlocalContext.refresh();\n\t\tDefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource,\n\t\t\t\tTaskProperties.DEFAULT_TABLE_PREFIX, localContext);\n\t\tassertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())\n\t\t\t.isEqualTo(\"org.springframework.orm.jpa.JpaTransactionManager\");\n\t}\n\n\t@Test\n\tpublic void dataSourceTransactionManagerTest() {\n\t\tDefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource);\n\t\tassertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())\n\t\t\t.isEqualTo(\"org.springframework.jdbc.support.JdbcTransactionManager\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, \"FOO\", null);\n\t\tassertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())\n\t\t\t.isEqualTo(\"org.springframework.jdbc.support.JdbcTransactionManager\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, \"FOO\", this.context);\n\t\tassertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())\n\t\t\t.isEqualTo(\"org.springframework.jdbc.support.JdbcTransactionManager\");\n\t}\n\n\t@Test\n\tpublic void taskExplorerTest() {\n\t\tDefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource);\n\t\tassertThat(defaultTaskConfigurer.getTaskExplorer()).isNotNull();\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer();\n\t\tassertThat(defaultTaskConfigurer.getTaskExplorer()).isNotNull();\n\t}\n\n\t@Test\n\tpublic void taskNameResolverTest() {\n\t\tDefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource);\n\t\tassertThat(defaultTaskConfigurer.getTaskNameResolver()).isNotNull();\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer();\n\t\tassertThat(defaultTaskConfigurer.getTaskNameResolver()).isNotNull();\n\t}\n\n\t@Test\n\tpublic void taskRepositoryTest() {\n\t\tDefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource);\n\t\tassertThat(defaultTaskConfigurer.getTaskRepository()).isNotNull();\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer();\n\t\tassertThat(defaultTaskConfigurer.getTaskRepository()).isNotNull();\n\t}\n\n\t@Test\n\tpublic void taskDataSource() {\n\t\tDefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource);\n\t\tassertThat(defaultTaskConfigurer.getTaskDataSource()).isNotNull();\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer();\n\t\tassertThat(defaultTaskConfigurer.getTaskDataSource()).isNull();\n\t}\n\n\t@Test\n\tpublic void taskDataSourceWithProperties() {\n\t\tTaskProperties taskProperties = new TaskProperties();\n\t\ttaskProperties.setTablePrefix(\"foo\");\n\t\tDefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, taskProperties);\n\t\tassertThat(defaultTaskConfigurer.getTaskDataSource()).isNotNull();\n\t\tString prefix = getPrefix(defaultTaskConfigurer);\n\t\tassertThat(prefix).isEqualTo(\"foo\");\n\t\tSystem.out.println(prefix);\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer();\n\t\tvalidatePrefix(defaultTaskConfigurer, \"TASK_\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(taskProperties);\n\t\tvalidatePrefix(defaultTaskConfigurer, \"TASK_\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource);\n\t\tvalidatePrefix(defaultTaskConfigurer, \"TASK_\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, taskProperties);\n\t\tvalidatePrefix(defaultTaskConfigurer, \"foo\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, new TaskProperties());\n\t\tvalidatePrefix(defaultTaskConfigurer, \"TASK_\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, null, null);\n\t\tvalidatePrefix(defaultTaskConfigurer, \"TASK_\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, \"bar\", null);\n\t\tvalidatePrefix(defaultTaskConfigurer, \"bar\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, \"bar\", null, null);\n\t\tvalidatePrefix(defaultTaskConfigurer, \"bar\");\n\t\tdefaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, \"bar\", null, taskProperties);\n\t\tvalidatePrefix(defaultTaskConfigurer, \"bar\");\n\t}\n\n\tprivate void validatePrefix(DefaultTaskConfigurer defaultTaskConfigurer, String prefix) {\n\t\tString result = getPrefix(defaultTaskConfigurer);\n\t\tassertThat(result).isEqualTo(prefix);\n\t}\n\n\tprivate String getPrefix(DefaultTaskConfigurer defaultTaskConfigurer) {\n\t\tSimpleTaskRepository taskRepository = (SimpleTaskRepository) ReflectionTestUtils.getField(defaultTaskConfigurer,\n\t\t\t\t\"taskRepository\");\n\t\tTaskExecutionDaoFactoryBean factoryBean = (TaskExecutionDaoFactoryBean) ReflectionTestUtils\n\t\t\t.getField(taskRepository, \"taskExecutionDaoFactoryBean\");\n\t\treturn (String) ReflectionTestUtils.getField(factoryBean, \"tablePrefix\");\n\t}\n\n\t@Configuration\n\tpublic static class EntityManagerConfiguration {\n\n\t\t@Bean\n\t\tpublic EntityManager entityManager() {\n\t\t\treturn mock(EntityManager.class);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/RepositoryTransactionManagerConfigurationTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.listener.TaskLifecycleListener;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.jdbc.support.JdbcTransactionManager;\nimport org.springframework.test.jdbc.JdbcTestUtils;\nimport org.springframework.test.util.ReflectionTestUtils;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.support.DefaultTransactionStatus;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Michael Minella\n * @author Mahmoud Ben Hassine\n */\npublic class RepositoryTransactionManagerConfigurationTests {\n\n\t@Test\n\tpublic void testZeroCustomTransactionManagerConfiguration() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, ZeroTransactionManagerConfiguration.class))\n\t\t\t.withPropertyValues(\"application.name=transactionManagerTask\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tDataSource dataSource = context.getBean(\"dataSource\", DataSource.class);\n\n\t\t\tint taskExecutionCount = JdbcTestUtils.countRowsInTable(new JdbcTemplate(dataSource), \"TASK_EXECUTION\");\n\n\t\t\tassertThat(taskExecutionCount).isEqualTo(1);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testSingleCustomTransactionManagerConfiguration() {\n\t\ttestConfiguration(SingleTransactionManagerConfiguration.class);\n\t}\n\n\t@Test\n\tpublic void testMultipleCustomTransactionManagerConfiguration() {\n\t\ttestConfiguration(MultipleTransactionManagerConfiguration.class);\n\t}\n\n\tprivate void testConfiguration(Class configurationClass) {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, configurationClass))\n\t\t\t.withPropertyValues(\"application.name=transactionManagerTask\");\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tDataSource dataSource = context.getBean(\"dataSource\", DataSource.class);\n\n\t\t\tint taskExecutionCount = JdbcTestUtils.countRowsInTable(new JdbcTemplate(dataSource), \"TASK_EXECUTION\");\n\n\t\t\t// Verify that the create call was rolled back\n\t\t\tassertThat(taskExecutionCount).isEqualTo(0);\n\n\t\t\t// Execute a new create call so that things close cleanly\n\t\t\tTaskRepository taskRepository = context.getBean(\"taskRepository\", TaskRepository.class);\n\n\t\t\tTaskExecution taskExecution = taskRepository.createTaskExecution(\"transactionManagerTask\");\n\t\t\ttaskExecution = taskRepository.startTaskExecution(taskExecution.getExecutionId(),\n\t\t\t\t\ttaskExecution.getTaskName(), LocalDateTime.now(), new ArrayList<>(0), null);\n\n\t\t\tTaskLifecycleListener listener = context.getBean(TaskLifecycleListener.class);\n\n\t\t\tReflectionTestUtils.setField(listener, \"taskExecution\", taskExecution);\n\t\t});\n\t}\n\n\t@EnableTask\n\t@Configuration\n\tpublic static class ZeroTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\tpublic TaskConfigurer taskConfigurer(DataSource dataSource) {\n\t\t\treturn new DefaultTaskConfigurer(dataSource);\n\t\t}\n\n\t\t@Bean\n\t\tpublic DataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();\n\t\t}\n\n\t}\n\n\t@EnableTask\n\t@Configuration\n\tpublic static class SingleTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\tpublic TaskConfigurer taskConfigurer(DataSource dataSource, PlatformTransactionManager transactionManager) {\n\t\t\treturn new DefaultTaskConfigurer(dataSource) {\n\t\t\t\t@Override\n\t\t\t\tpublic PlatformTransactionManager getTransactionManager() {\n\t\t\t\t\treturn transactionManager;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tpublic DataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic JdbcTransactionManager transactionManager(DataSource dataSource) {\n\t\t\treturn new TestJdbcTransactionManager(dataSource);\n\t\t}\n\n\t}\n\n\t@EnableTask\n\t@Configuration\n\tpublic static class MultipleTransactionManagerConfiguration {\n\n\t\t@Bean\n\t\tpublic TaskConfigurer taskConfigurer(DataSource dataSource, PlatformTransactionManager transactionManager) {\n\t\t\treturn new DefaultTaskConfigurer(dataSource) {\n\t\t\t\t@Override\n\t\t\t\tpublic PlatformTransactionManager getTransactionManager() {\n\t\t\t\t\treturn transactionManager;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t@Bean\n\t\tpublic DataSource dataSource() {\n\t\t\treturn new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic JdbcTransactionManager transactionManager(DataSource dataSource) {\n\t\t\treturn new TestJdbcTransactionManager(dataSource);\n\t\t}\n\n\t\t@Bean\n\t\tpublic DataSource dataSource2() {\n\t\t\treturn new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic JdbcTransactionManager transactionManager2(DataSource dataSource2) {\n\t\t\treturn new JdbcTransactionManager(dataSource2);\n\t\t}\n\n\t}\n\n\tprivate static class TestJdbcTransactionManager extends JdbcTransactionManager {\n\n\t\tprotected TestJdbcTransactionManager(DataSource dataSource) {\n\t\t\tsuper(dataSource);\n\t\t}\n\n\t\tprivate int count = 0;\n\n\t\t@Override\n\t\tprotected void doCommit(DefaultTransactionStatus status) {\n\n\t\t\tif (count == 0) {\n\t\t\t\t// Rollback the finish of the task\n\t\t\t\tsuper.doRollback(status);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Commit the start of the task\n\t\t\t\tsuper.doCommit(status);\n\t\t\t}\n\n\t\t\tcount++;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TaskPropertiesTests.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\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.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@DirtiesContext\n@ExtendWith(SpringExtension.class)\n@SpringBootTest(classes = { SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class },\n\t\tproperties = { \"spring.cloud.task.closecontextEnabled=false\", \"spring.cloud.task.initialize-enabled=false\" })\npublic class TaskPropertiesTests {\n\n\t@Autowired\n\tTaskProperties taskProperties;\n\n\t@Test\n\tpublic void test() {\n\t\tassertThat(this.taskProperties.getClosecontextEnabled()).isFalse();\n\t\tassertThat(this.taskProperties.isInitializeEnabled()).isFalse();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TestConfiguration.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.batch.infrastructure.support.transaction.ResourcelessTransactionManager;\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.repository.support.SimpleTaskExplorer;\nimport org.springframework.cloud.task.repository.support.SimpleTaskRepository;\nimport org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean;\nimport org.springframework.cloud.task.repository.support.TaskRepositoryInitializer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ResourceLoader;\nimport org.springframework.jdbc.support.JdbcTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * @author Michael Minella\n * @author Mahmoud Ben Hassine\n */\n\n@Configuration\npublic class TestConfiguration implements InitializingBean {\n\n\t@Autowired(required = false)\n\tprivate DataSource dataSource;\n\n\t@Autowired(required = false)\n\tprivate ResourceLoader resourceLoader;\n\n\tprivate TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean;\n\n\t@Bean\n\tpublic TaskRepositoryInitializer taskRepositoryInitializer() throws Exception {\n\t\tTaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer(new TaskProperties());\n\t\ttaskRepositoryInitializer.setDataSource(this.dataSource);\n\t\ttaskRepositoryInitializer.setResourceLoader(this.resourceLoader);\n\t\ttaskRepositoryInitializer.afterPropertiesSet();\n\n\t\treturn taskRepositoryInitializer;\n\t}\n\n\t@Bean\n\tpublic TaskExplorer taskExplorer() {\n\t\treturn new SimpleTaskExplorer(this.taskExecutionDaoFactoryBean);\n\t}\n\n\t@Bean\n\tpublic TaskRepository taskRepository() {\n\t\treturn new SimpleTaskRepository(this.taskExecutionDaoFactoryBean);\n\t}\n\n\t@Bean\n\tpublic PlatformTransactionManager transactionManager() {\n\t\tif (this.dataSource == null) {\n\t\t\treturn new ResourcelessTransactionManager();\n\t\t}\n\t\telse {\n\t\t\treturn new JdbcTransactionManager(this.dataSource);\n\t\t}\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() {\n\t\tif (this.dataSource != null) {\n\t\t\tthis.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(this.dataSource);\n\t\t}\n\t\telse {\n\t\t\tthis.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/observation/ObservationIntegrationTests.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.configuration.observation;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport brave.sampler.Sampler;\nimport brave.test.TestSpanHandler;\nimport io.micrometer.common.KeyValues;\nimport io.micrometer.core.instrument.MeterRegistry;\nimport io.micrometer.core.tck.MeterRegistryAssert;\nimport io.micrometer.tracing.Tracer;\nimport io.micrometer.tracing.brave.bridge.BraveFinishedSpan;\nimport io.micrometer.tracing.exporter.FinishedSpan;\nimport io.micrometer.tracing.test.simple.SpansAssert;\nimport org.junit.jupiter.api.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.CompositeMeterRegistryAutoConfiguration;\nimport org.springframework.boot.micrometer.metrics.autoconfigure.MetricsAutoConfiguration;\nimport org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.brave.autoconfigure.BraveAutoConfiguration;\nimport org.springframework.boot.micrometer.tracing.test.autoconfigure.AutoConfigureTracing;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.zipkin.autoconfigure.ZipkinAutoConfiguration;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@AutoConfigureTracing\n@SpringBootTest(classes = ObservationIntegrationTests.Config.class)\nclass ObservationIntegrationTests {\n\n\t@Autowired\n\tTestSpanHandler testSpanHandler;\n\n\t@Autowired\n\tMeterRegistry meterRegistry;\n\n\t@Test\n\tvoid testSuccessfulObservation() {\n\t\tList<FinishedSpan> finishedSpans = finishedSpans();\n\n\t\tSpansAssert.then(finishedSpans)\n\t\t\t.thenASpanWithNameEqualTo(\"myCommandLineRunner\")\n\t\t\t.hasTag(\"spring.cloud.task.runner.bean-name\", \"myCommandLineRunner\")\n\t\t\t.backToSpans()\n\t\t\t.thenASpanWithNameEqualTo(\"myApplicationRunner\")\n\t\t\t.hasTag(\"spring.cloud.task.runner.bean-name\", \"myApplicationRunner\");\n\t\tMeterRegistryAssert.then(this.meterRegistry)\n\t\t\t.hasTimerWithNameAndTags(\"spring.cloud.task.runner\",\n\t\t\t\t\tKeyValues.of(\"spring.cloud.task.runner.bean-name\", \"myCommandLineRunner\"))\n\t\t\t.hasTimerWithNameAndTags(\"spring.cloud.task.runner\",\n\t\t\t\t\tKeyValues.of(\"spring.cloud.task.runner.bean-name\", \"myApplicationRunner\"));\n\t}\n\n\tprivate List<FinishedSpan> finishedSpans() {\n\t\treturn this.testSpanHandler.spans().stream().map(BraveFinishedSpan::fromBrave).collect(Collectors.toList());\n\t}\n\n\t@Configuration\n\t@EnableTask\n\t@ImportAutoConfiguration({ SimpleTaskAutoConfiguration.class, ObservationAutoConfiguration.class,\n\t\t\tObservationTaskAutoConfiguration.class, BraveAutoConfiguration.class,\n\t\t\tMicrometerTracingAutoConfiguration.class, MetricsAutoConfiguration.class,\n\t\t\tCompositeMeterRegistryAutoConfiguration.class, ZipkinAutoConfiguration.class })\n\tstatic class Config {\n\n\t\tprivate static final Logger log = LoggerFactory.getLogger(Config.class);\n\n\t\t@Bean\n\t\tTestSpanHandler testSpanHandler() {\n\t\t\treturn new TestSpanHandler();\n\t\t}\n\n\t\t@Bean\n\t\tSampler sampler() {\n\t\t\treturn Sampler.ALWAYS_SAMPLE;\n\t\t}\n\n\t\t@Bean\n\t\tCommandLineRunner myCommandLineRunner(Tracer tracer) {\n\t\t\treturn args -> log.info(\"<TRACE:{}> Hello from command line runner\",\n\t\t\t\t\ttracer.currentSpan().context().traceId());\n\t\t}\n\n\t\t@Bean\n\t\tApplicationRunner myApplicationRunner(Tracer tracer) {\n\t\t\treturn args -> log.info(\"<TRACE:{}> Hello from application runner\",\n\t\t\t\t\ttracer.currentSpan().context().traceId());\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExceptionTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n */\npublic class TaskExceptionTests {\n\n\tprivate static final String ERROR_MESSAGE = \"ERROR MESSAGE\";\n\n\t@Test\n\tpublic void testTaskException() {\n\t\tTaskException taskException = new TaskException(ERROR_MESSAGE);\n\t\tassertThat(taskException.getMessage()).isEqualTo(ERROR_MESSAGE);\n\n\t\ttaskException = new TaskException(ERROR_MESSAGE, new IllegalStateException(ERROR_MESSAGE));\n\t\tassertThat(taskException.getMessage()).isEqualTo(ERROR_MESSAGE);\n\t\tassertThat(taskException.getCause()).isNotNull();\n\t\tassertThat(taskException.getCause().getMessage()).isEqualTo(ERROR_MESSAGE);\n\t}\n\n\t@Test\n\tpublic void testTaskExecutionException() {\n\t\tTaskExecutionException taskException = new TaskExecutionException(ERROR_MESSAGE);\n\t\tassertThat(taskException.getMessage()).isEqualTo(ERROR_MESSAGE);\n\n\t\ttaskException = new TaskExecutionException(ERROR_MESSAGE, new IllegalStateException(ERROR_MESSAGE));\n\t\tassertThat(taskException.getMessage()).isEqualTo(ERROR_MESSAGE);\n\t\tassertThat(taskException.getCause()).isNotNull();\n\t\tassertThat(taskException.getCause().getMessage()).isEqualTo(ERROR_MESSAGE);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport java.time.Duration;\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.cloud.task.listener.annotation.AfterTask;\nimport org.springframework.cloud.task.listener.annotation.BeforeTask;\nimport org.springframework.cloud.task.listener.annotation.FailedTask;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.util.TestDefaultConfiguration;\nimport org.springframework.cloud.task.util.TestListener;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Verifies that the TaskExecutionListener invocations occur at the appropriate task\n * lifecycle stages.\n *\n * @author Glenn Renfro\n */\npublic class TaskExecutionListenerTests {\n\n\tprivate static final String EXCEPTION_MESSAGE = \"This was expected\";\n\n\tprivate static boolean beforeTaskDidFireOnError = false;\n\n\tprivate static boolean endTaskDidFireOnError = false;\n\n\tprivate static boolean failedTaskDidFireOnError = false;\n\n\tprivate AnnotationConfigApplicationContext context;\n\n\t@BeforeTask\n\tpublic void setup() {\n\t\tbeforeTaskDidFireOnError = false;\n\t\tendTaskDidFireOnError = false;\n\t\tfailedTaskDidFireOnError = false;\n\t}\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.context != null && this.context.isActive()) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t/**\n\t * Verify that if a TaskExecutionListener Bean is present that the onTaskStartup\n\t * method is called.\n\t */\n\t@Test\n\tpublic void testTaskCreate() {\n\t\tsetupContextForTaskExecutionListener();\n\t\tDefaultTaskListenerConfiguration.TestTaskExecutionListener taskExecutionListener = this.context\n\t\t\t.getBean(DefaultTaskListenerConfiguration.TestTaskExecutionListener.class);\n\t\tTaskExecution taskExecution = new TaskExecution(0, null, \"wombat\", LocalDateTime.now(), LocalDateTime.now(),\n\t\t\t\tnull, new ArrayList<>(), null, null);\n\t\tverifyListenerResults(false, false, taskExecution, taskExecutionListener);\n\t}\n\n\t/**\n\t * Verify that if a LifecycleProcessor executes all TaskExecutionListeners if\n\t * BeforeTask throws exception.\n\t */\n\t@Test\n\tpublic void testBeforeTaskErrorCreate() {\n\t\tboolean exceptionFired = false;\n\t\ttry {\n\t\t\tsetupContextForBeforeTaskErrorAnnotatedListener();\n\t\t}\n\t\tcatch (Exception exception) {\n\t\t\texceptionFired = true;\n\t\t}\n\t\tassertThat(exceptionFired).as(\"Exception should have fired\").isTrue();\n\t\tassertThat(beforeTaskDidFireOnError).as(\"BeforeTask Listener should have executed\").isTrue();\n\t\tassertThat(endTaskDidFireOnError).as(\"EndTask Listener should have executed\").isTrue();\n\t\tassertThat(failedTaskDidFireOnError).as(\"FailedTask Listener should have executed\").isTrue();\n\t}\n\n\t/**\n\t * Verify that if a LifecycleProcessor executes AfterTask TaskExecutionListeners if\n\t * FailedTask throws exception.\n\t */\n\t@Test\n\tpublic void testFailedTaskErrorCreate() {\n\t\tboolean exceptionFired = false;\n\t\ttry {\n\t\t\tsetupContextForFailedTaskErrorAnnotatedListener();\n\t\t}\n\t\tcatch (Exception exception) {\n\t\t\texceptionFired = true;\n\t\t}\n\t\tassertThat(exceptionFired).as(\"Exception should have fired\").isTrue();\n\t\tassertThat(endTaskDidFireOnError).as(\"EndTask Listener should have executed\").isTrue();\n\t\tassertThat(failedTaskDidFireOnError).as(\"FailedTask Listener should not have executed\").isTrue();\n\t}\n\n\t/**\n\t * Verify that if a LifecycleProcessor stores the correct exit code if AfterTask\n\t * listener fails.\n\t */\n\t@Test\n\tpublic void testAfterTaskErrorCreate() {\n\t\tsetupContextForAfterTaskErrorAnnotatedListener();\n\t\tAfterTaskErrorAnnotationConfiguration.AnnotatedTaskListener taskExecutionListener = this.context\n\t\t\t.getBean(AfterTaskErrorAnnotationConfiguration.AnnotatedTaskListener.class);\n\t\tthis.context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], this.context,\n\t\t\t\tDuration.ofSeconds(50)));\n\n\t\tassertThat(taskExecutionListener.isTaskStartup()).isTrue();\n\t\tassertThat(taskExecutionListener.isTaskEnd()).isTrue();\n\t\tassertThat(taskExecutionListener.getTaskExecution().getExitMessage()).isEqualTo(TestListener.END_MESSAGE);\n\t\tassertThat(taskExecutionListener.getTaskExecution()\n\t\t\t.getErrorMessage()\n\t\t\t.contains(\"Failed to process @BeforeTask or @AfterTask annotation because: AfterTaskFailure\")).isTrue();\n\t\tassertThat(taskExecutionListener.getThrowable()).isNull();\n\t}\n\n\t/**\n\t * Verify that if a TaskExecutionListener Bean is present that the onTaskEnd method is\n\t * called.\n\t */\n\t@Test\n\tpublic void testTaskUpdate() {\n\t\tsetupContextForTaskExecutionListener();\n\t\tDefaultTaskListenerConfiguration.TestTaskExecutionListener taskExecutionListener = this.context\n\t\t\t.getBean(DefaultTaskListenerConfiguration.TestTaskExecutionListener.class);\n\t\tthis.context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], this.context,\n\t\t\t\tDuration.ofSeconds(50)));\n\n\t\tTaskExecution taskExecution = new TaskExecution(0, 0, \"wombat\", LocalDateTime.now(), LocalDateTime.now(), null,\n\t\t\t\tnew ArrayList<>(), null, null);\n\t\tverifyListenerResults(true, false, taskExecution, taskExecutionListener);\n\t}\n\n\t/**\n\t * Verify that if a TaskExecutionListener Bean is present that the onTaskFailed method\n\t * is called.\n\t */\n\t@Test\n\tpublic void testTaskFail() {\n\t\tRuntimeException exception = new RuntimeException(EXCEPTION_MESSAGE);\n\t\tsetupContextForTaskExecutionListener();\n\t\tSpringApplication application = new SpringApplication();\n\t\tDefaultTaskListenerConfiguration.TestTaskExecutionListener taskExecutionListener = this.context\n\t\t\t.getBean(DefaultTaskListenerConfiguration.TestTaskExecutionListener.class);\n\t\tthis.context.publishEvent(new ApplicationFailedEvent(application, new String[0], this.context, exception));\n\t\tthis.context\n\t\t\t.publishEvent(new ApplicationReadyEvent(application, new String[0], this.context, Duration.ofSeconds(50)));\n\n\t\tTaskExecution taskExecution = new TaskExecution(0, 1, \"wombat\", LocalDateTime.now(), LocalDateTime.now(), null,\n\t\t\t\tnew ArrayList<>(), null, null);\n\t\tverifyListenerResults(true, true, taskExecution, taskExecutionListener);\n\t}\n\n\t/**\n\t * Verify that if a bean has a @BeforeTask annotation present that the associated\n\t * method is called.\n\t */\n\t@Test\n\tpublic void testAnnotationCreate() {\n\t\tsetupContextForAnnotatedListener();\n\t\tDefaultAnnotationConfiguration.AnnotatedTaskListener annotatedListener = this.context\n\t\t\t.getBean(DefaultAnnotationConfiguration.AnnotatedTaskListener.class);\n\t\tTaskExecution taskExecution = new TaskExecution(0, null, \"wombat\", LocalDateTime.now(), LocalDateTime.now(),\n\t\t\t\tnull, new ArrayList<>(), null, null);\n\t\tverifyListenerResults(false, false, taskExecution, annotatedListener);\n\t}\n\n\t/**\n\t * Verify that if a bean has a @AfterTask annotation present that the associated\n\t * method is called.\n\t */\n\t@Test\n\tpublic void testAnnotationUpdate() {\n\t\tsetupContextForAnnotatedListener();\n\t\tDefaultAnnotationConfiguration.AnnotatedTaskListener annotatedListener = this.context\n\t\t\t.getBean(DefaultAnnotationConfiguration.AnnotatedTaskListener.class);\n\t\tthis.context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], this.context,\n\t\t\t\tDuration.ofSeconds(50)));\n\n\t\tTaskExecution taskExecution = new TaskExecution(0, 0, \"wombat\", LocalDateTime.now(), LocalDateTime.now(), null,\n\t\t\t\tnew ArrayList<>(), null, null);\n\t\tverifyListenerResults(true, false, taskExecution, annotatedListener);\n\t}\n\n\t/**\n\t * Verify that if a bean has a @FailedTask annotation present that the associated\n\t * method is called.\n\t */\n\t@Test\n\tpublic void testAnnotationFail() {\n\t\tRuntimeException exception = new RuntimeException(EXCEPTION_MESSAGE);\n\t\tsetupContextForAnnotatedListener();\n\t\tSpringApplication application = new SpringApplication();\n\t\tDefaultAnnotationConfiguration.AnnotatedTaskListener annotatedListener = this.context\n\t\t\t.getBean(DefaultAnnotationConfiguration.AnnotatedTaskListener.class);\n\t\tthis.context.publishEvent(new ApplicationFailedEvent(application, new String[0], this.context, exception));\n\t\tthis.context\n\t\t\t.publishEvent(new ApplicationReadyEvent(application, new String[0], this.context, Duration.ofSeconds(50)));\n\n\t\tTaskExecution taskExecution = new TaskExecution(0, 1, \"wombat\", LocalDateTime.now(), LocalDateTime.now(), null,\n\t\t\t\tnew ArrayList<>(), null, null);\n\t\tverifyListenerResults(true, true, taskExecution, annotatedListener);\n\t}\n\n\tprivate void verifyListenerResults(boolean isTaskEnd, boolean isTaskFailed, TaskExecution taskExecution,\n\t\t\tTestListener actualListener) {\n\t\tassertThat(actualListener.isTaskStartup()).isTrue();\n\t\tassertThat(actualListener.isTaskEnd()).isEqualTo(isTaskEnd);\n\t\tassertThat(actualListener.isTaskFailed()).isEqualTo(isTaskFailed);\n\t\tif (isTaskFailed) {\n\t\t\tassertThat(actualListener.getTaskExecution().getExitMessage()).isEqualTo(TestListener.END_MESSAGE);\n\t\t\tassertThat(actualListener.getThrowable()).isNotNull();\n\t\t\tassertThat(actualListener.getThrowable() instanceof RuntimeException).isTrue();\n\t\t\tassertThat(actualListener.getTaskExecution()\n\t\t\t\t.getErrorMessage()\n\t\t\t\t.startsWith(\"java.lang.RuntimeException: This was expected\")).isTrue();\n\t\t}\n\t\telse if (isTaskEnd) {\n\t\t\tassertThat(actualListener.getTaskExecution().getExitMessage()).isEqualTo(TestListener.END_MESSAGE);\n\t\t\tassertThat(actualListener.getTaskExecution().getErrorMessage()).isEqualTo(taskExecution.getErrorMessage());\n\t\t\tassertThat(actualListener.getThrowable()).isNull();\n\t\t}\n\t\telse {\n\t\t\tassertThat(actualListener.getTaskExecution().getExitMessage()).isEqualTo(TestListener.START_MESSAGE);\n\t\t\tassertThat(actualListener.getTaskExecution().getErrorMessage()).isNull();\n\t\t\tassertThat(actualListener.getThrowable()).isNull();\n\t\t}\n\n\t\tassertThat(actualListener.getTaskExecution().getExecutionId()).isEqualTo(taskExecution.getExecutionId());\n\t\tassertThat(actualListener.getTaskExecution().getExitCode()).isEqualTo(taskExecution.getExitCode());\n\t\tassertThat(actualListener.getTaskExecution().getExternalExecutionId())\n\t\t\t.isEqualTo(taskExecution.getExternalExecutionId());\n\t}\n\n\tprivate void setupContextForTaskExecutionListener() {\n\t\tthis.context = new AnnotationConfigApplicationContext(DefaultTaskListenerConfiguration.class,\n\t\t\t\tTestDefaultConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.setId(\"testTask\");\n\t}\n\n\tprivate void setupContextForAnnotatedListener() {\n\t\tthis.context = new AnnotationConfigApplicationContext(TestDefaultConfiguration.class,\n\t\t\t\tDefaultAnnotationConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.setId(\"annotatedTask\");\n\t}\n\n\tprivate void setupContextForBeforeTaskErrorAnnotatedListener() {\n\t\tthis.context = new AnnotationConfigApplicationContext(TestDefaultConfiguration.class,\n\t\t\t\tBeforeTaskErrorAnnotationConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.setId(\"beforeTaskAnnotatedTask\");\n\t}\n\n\tprivate void setupContextForFailedTaskErrorAnnotatedListener() {\n\t\tthis.context = new AnnotationConfigApplicationContext(TestDefaultConfiguration.class,\n\t\t\t\tFailedTaskErrorAnnotationConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.setId(\"failedTaskAnnotatedTask\");\n\t}\n\n\tprivate void setupContextForAfterTaskErrorAnnotatedListener() {\n\t\tthis.context = new AnnotationConfigApplicationContext(TestDefaultConfiguration.class,\n\t\t\t\tAfterTaskErrorAnnotationConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.setId(\"afterTaskAnnotatedTask\");\n\t}\n\n\t@Configuration\n\tpublic static class DefaultAnnotationConfiguration {\n\n\t\t@Bean\n\t\tpublic AnnotatedTaskListener annotatedTaskListener() {\n\t\t\treturn new AnnotatedTaskListener();\n\t\t}\n\n\t\tpublic static class AnnotatedTaskListener extends TestListener {\n\n\t\t\t@BeforeTask\n\t\t\tpublic void methodA(TaskExecution taskExecution) {\n\t\t\t\tthis.isTaskStartup = true;\n\t\t\t\tthis.taskExecution = taskExecution;\n\t\t\t\tthis.taskExecution.setExitMessage(START_MESSAGE);\n\t\t\t}\n\n\t\t\t@AfterTask\n\t\t\tpublic void methodB(TaskExecution taskExecution) {\n\t\t\t\tthis.isTaskEnd = true;\n\t\t\t\tthis.taskExecution = taskExecution;\n\t\t\t\tthis.taskExecution.setExitMessage(END_MESSAGE);\n\n\t\t\t}\n\n\t\t\t@FailedTask\n\t\t\tpublic void methodC(TaskExecution taskExecution, Throwable throwable) {\n\t\t\t\tthis.isTaskFailed = true;\n\t\t\t\tthis.taskExecution = taskExecution;\n\t\t\t\tthis.throwable = throwable;\n\t\t\t\tthis.taskExecution.setExitMessage(ERROR_MESSAGE);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class BeforeTaskErrorAnnotationConfiguration {\n\n\t\t@Bean\n\t\tpublic AnnotatedTaskListener annotatedTaskListener() {\n\t\t\treturn new AnnotatedTaskListener();\n\t\t}\n\n\t\t@Bean\n\t\tpublic CommandLineRunner commandLineRunner() {\n\t\t\treturn args -> System.out.println(\"I was run\");\n\t\t}\n\n\t\tpublic static class AnnotatedTaskListener {\n\n\t\t\t@BeforeTask\n\t\t\tpublic void methodA(TaskExecution taskExecution) {\n\t\t\t\tbeforeTaskDidFireOnError = true;\n\t\t\t\tthrow new TaskExecutionException(\"BeforeTaskFailure\");\n\t\t\t}\n\n\t\t\t@AfterTask\n\t\t\tpublic void methodB(TaskExecution taskExecution) {\n\t\t\t\tendTaskDidFireOnError = true;\n\t\t\t}\n\n\t\t\t@FailedTask\n\t\t\tpublic void methodC(TaskExecution taskExecution, Throwable throwable) {\n\t\t\t\tfailedTaskDidFireOnError = true;\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class FailedTaskErrorAnnotationConfiguration {\n\n\t\t@Bean\n\t\tpublic AnnotatedTaskListener annotatedTaskListener() {\n\t\t\treturn new AnnotatedTaskListener();\n\t\t}\n\n\t\tpublic static class AnnotatedTaskListener {\n\n\t\t\t@BeforeTask\n\t\t\tpublic void methodA(TaskExecution taskExecution) {\n\t\t\t\tbeforeTaskDidFireOnError = true;\n\t\t\t\tthrow new TaskExecutionException(\"BeforeTaskFailure\");\n\t\t\t}\n\n\t\t\t@AfterTask\n\t\t\tpublic void methodB(TaskExecution taskExecution) {\n\t\t\t\tendTaskDidFireOnError = true;\n\t\t\t}\n\n\t\t\t@FailedTask\n\t\t\tpublic void methodC(TaskExecution taskExecution, Throwable throwable) {\n\t\t\t\tfailedTaskDidFireOnError = true;\n\t\t\t\tthrow new TaskExecutionException(\"FailedTaskFailure\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class AfterTaskErrorAnnotationConfiguration {\n\n\t\t@Bean\n\t\tpublic AnnotatedTaskListener annotatedTaskListener() {\n\t\t\treturn new AnnotatedTaskListener();\n\t\t}\n\n\t\tpublic static class AnnotatedTaskListener extends TestListener {\n\n\t\t\t@BeforeTask\n\t\t\tpublic void methodA(TaskExecution taskExecution) {\n\t\t\t\tthis.isTaskStartup = true;\n\t\t\t}\n\n\t\t\t@AfterTask\n\t\t\tpublic void methodB(TaskExecution taskExecution) {\n\t\t\t\tthis.isTaskEnd = true;\n\t\t\t\tthis.taskExecution = taskExecution;\n\t\t\t\tthis.taskExecution.setExitMessage(END_MESSAGE);\n\t\t\t\tthrow new TaskExecutionException(\"AfterTaskFailure\");\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class DefaultTaskListenerConfiguration {\n\n\t\t@Bean\n\t\tpublic TestTaskExecutionListener taskExecutionListener() {\n\t\t\treturn new TestTaskExecutionListener();\n\t\t}\n\n\t\tpublic static class TestTaskExecutionListener extends TestListener implements TaskExecutionListener {\n\n\t\t\t@Override\n\t\t\tpublic void onTaskStartup(TaskExecution taskExecution) {\n\t\t\t\tthis.isTaskStartup = true;\n\t\t\t\tthis.taskExecution = taskExecution;\n\t\t\t\tthis.taskExecution.setExitMessage(START_MESSAGE);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onTaskEnd(TaskExecution taskExecution) {\n\t\t\t\tthis.isTaskEnd = true;\n\t\t\t\tthis.taskExecution = taskExecution;\n\t\t\t\tthis.taskExecution.setExitMessage(END_MESSAGE);\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {\n\t\t\t\tthis.isTaskFailed = true;\n\t\t\t\tthis.taskExecution = taskExecution;\n\t\t\t\tthis.throwable = throwable;\n\t\t\t\tthis.taskExecution.setExitMessage(ERROR_MESSAGE);\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskLifecycleListenerTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.tck.TestObservationRegistry;\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;\n\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ExitCodeEvent;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.context.event.ApplicationFailedEvent;\nimport org.springframework.boot.context.event.ApplicationReadyEvent;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.util.TestDefaultConfiguration;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Sort;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Verifies that the TaskLifecycleListener Methods record the appropriate log header\n * entries and result codes.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n */\n@ExtendWith(OutputCaptureExtension.class)\npublic class TaskLifecycleListenerTests {\n\n\tprivate AnnotationConfigApplicationContext context;\n\n\tprivate TaskExplorer taskExplorer;\n\n\t@BeforeEach\n\tpublic void setUp() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.setId(\"testTask\");\n\t\tthis.context.register(TestDefaultConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tTestListener.getStartupOrderList().clear();\n\t\tTestListener.getFailOrderList().clear();\n\t\tTestListener.getEndOrderList().clear();\n\n\t}\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.context != null && this.context.isActive()) {\n\t\t\tthis.context.close();\n\t\t}\n\t\tObservationRegistry observationRegistry = TestObservationRegistry.create();\n\t\tif (observationRegistry.getCurrentObservationScope() != null) {\n\t\t\tObservation.Scope scope = observationRegistry.getCurrentObservationScope();\n\t\t\tscope.close();\n\t\t\tscope.getCurrentObservation().stop();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testTaskCreate() {\n\t\tthis.context.refresh();\n\t\tthis.taskExplorer = this.context.getBean(TaskExplorer.class);\n\t\tverifyTaskExecution(0, false);\n\t}\n\n\t@Test\n\tpublic void testTaskCreateWithArgs() {\n\t\tthis.context.register(ArgsConfiguration.class);\n\t\tthis.context.refresh();\n\t\tthis.taskExplorer = this.context.getBean(TaskExplorer.class);\n\t\tverifyTaskExecution(2, false);\n\t}\n\n\t@Test\n\tpublic void testTaskUpdate() {\n\t\tthis.context.refresh();\n\t\tthis.taskExplorer = this.context.getBean(TaskExplorer.class);\n\n\t\tthis.context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], this.context,\n\t\t\t\tDuration.ofSeconds(50)));\n\n\t\tverifyTaskExecution(0, true, 0);\n\t}\n\n\t@Test\n\tpublic void testTaskFailedUpdate() {\n\t\tthis.context.refresh();\n\t\tRuntimeException exception = new RuntimeException(\"This was expected\");\n\t\tSpringApplication application = new SpringApplication();\n\t\tthis.taskExplorer = this.context.getBean(TaskExplorer.class);\n\t\tthis.context.publishEvent(new ApplicationFailedEvent(application, new String[0], this.context, exception));\n\t\tthis.context\n\t\t\t.publishEvent(new ApplicationReadyEvent(application, new String[0], this.context, Duration.ofSeconds(50)));\n\n\t\tverifyTaskExecution(0, true, 1, exception, null);\n\t}\n\n\t@Test\n\tpublic void testTaskFailedWithExitCodeEvent() {\n\t\tfinal int exitCode = 10;\n\t\tthis.context.register(TestListener.class);\n\t\tthis.context.register(TestListener2.class);\n\n\t\tthis.context.refresh();\n\t\tRuntimeException exception = new RuntimeException(\"This was expected\");\n\t\tSpringApplication application = new SpringApplication();\n\t\tthis.taskExplorer = this.context.getBean(TaskExplorer.class);\n\t\tthis.context.publishEvent(new ExitCodeEvent(this.context, exitCode));\n\t\tthis.context.publishEvent(new ApplicationFailedEvent(application, new String[0], this.context, exception));\n\t\tthis.context\n\t\t\t.publishEvent(new ApplicationReadyEvent(application, new String[0], this.context, Duration.ofSeconds(50)));\n\n\t\tverifyTaskExecution(0, true, exitCode, exception, null);\n\t\tassertThat(TestListener.getStartupOrderList().size()).isEqualTo(2);\n\t\tassertThat(TestListener.getStartupOrderList().get(0)).isEqualTo(Integer.valueOf(2));\n\t\tassertThat(TestListener.getStartupOrderList().get(1)).isEqualTo(Integer.valueOf(1));\n\n\t\tassertThat(TestListener.getEndOrderList().size()).isEqualTo(2);\n\t\tassertThat(TestListener.getEndOrderList().get(0)).isEqualTo(Integer.valueOf(1));\n\t\tassertThat(TestListener.getEndOrderList().get(1)).isEqualTo(Integer.valueOf(2));\n\n\t\tassertThat(TestListener.getFailOrderList().size()).isEqualTo(2);\n\t\tassertThat(TestListener.getFailOrderList().get(0)).isEqualTo(Integer.valueOf(1));\n\t\tassertThat(TestListener.getFailOrderList().get(1)).isEqualTo(Integer.valueOf(2));\n\n\t}\n\n\t@Test\n\tpublic void testNoClosingOfContext() {\n\n\t\ttry (ConfigurableApplicationContext applicationContext = SpringApplication.run(\n\t\t\t\tnew Class[] { TestDefaultConfiguration.class, PropertyPlaceholderAutoConfiguration.class },\n\t\t\t\tnew String[] { \"--spring.cloud.task.closecontext_enabled=false\" })) {\n\t\t\tassertThat(applicationContext.isActive()).isTrue();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testInvalidTaskExecutionId() {\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(() -> {\n\t\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\t\tMap<String, Object> myMap = new HashMap<>();\n\t\t\tmyMap.put(\"spring.cloud.task.executionid\", \"55\");\n\t\t\tpropertySources.addFirst(new MapPropertySource(\"EnvrionmentTestPropsource\", myMap));\n\t\t\tthis.context.setEnvironment(environment);\n\t\t\tthis.context.refresh();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testRestartExistingTask(CapturedOutput capturedOutput) {\n\t\tthis.context.refresh();\n\n\t\tTaskLifecycleListener taskLifecycleListener = this.context.getBean(TaskLifecycleListener.class);\n\t\ttaskLifecycleListener.start();\n\t\tString output = capturedOutput.toString();\n\t\tassertThat(output.contains(\"Multiple start events have been received\"))\n\t\t\t.as(\"Test results do not show error message: \" + output)\n\t\t\t.isTrue();\n\t}\n\n\t@Test\n\tpublic void testExternalExecutionId() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tMap<String, Object> myMap = new HashMap<>();\n\t\tmyMap.put(\"spring.cloud.task.external-execution-id\", \"myid\");\n\t\tpropertySources.addFirst(new MapPropertySource(\"EnvrionmentTestPropsource\", myMap));\n\t\tthis.context.setEnvironment(environment);\n\t\tthis.context.refresh();\n\t\tthis.taskExplorer = this.context.getBean(TaskExplorer.class);\n\n\t\tverifyTaskExecution(0, false, null, null, \"myid\");\n\t}\n\n\t@Test\n\tpublic void testParentExecutionId() {\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tMap<String, Object> myMap = new HashMap<>();\n\t\tmyMap.put(\"spring.cloud.task.parentExecutionId\", 789);\n\t\tpropertySources.addFirst(new MapPropertySource(\"EnvrionmentTestPropsource\", myMap));\n\t\tthis.context.setEnvironment(environment);\n\t\tthis.context.refresh();\n\t\tthis.taskExplorer = this.context.getBean(TaskExplorer.class);\n\n\t\tverifyTaskExecution(0, false, null, null, null, 789L);\n\t}\n\n\tprivate void verifyTaskExecution(int numberOfParams, boolean update, Integer exitCode) {\n\t\tverifyTaskExecution(numberOfParams, update, exitCode, null, null);\n\t}\n\n\tprivate void verifyTaskExecution(int numberOfParams, boolean update) {\n\t\tverifyTaskExecution(numberOfParams, update, null, null, null);\n\t}\n\n\tprivate void verifyTaskExecution(int numberOfParams, boolean update, Integer exitCode, Throwable exception,\n\t\t\tString externalExecutionId) {\n\t\tverifyTaskExecution(numberOfParams, update, exitCode, exception, externalExecutionId, null);\n\t}\n\n\tprivate void verifyTaskExecution(int numberOfParams, boolean update, Integer exitCode, Throwable exception,\n\t\t\tString externalExecutionId, Long parentExecutionId) {\n\n\t\tSort sort = Sort.by(\"id\");\n\n\t\tPageRequest request = PageRequest.of(0, Integer.MAX_VALUE, sort);\n\n\t\tPage<TaskExecution> taskExecutionsByName = this.taskExplorer.findTaskExecutionsByName(\"testTask\", request);\n\t\tassertThat(taskExecutionsByName.iterator().hasNext()).isTrue();\n\t\tTaskExecution taskExecution = taskExecutionsByName.iterator().next();\n\n\t\tassertThat(taskExecution.getArguments().size()).isEqualTo(numberOfParams);\n\t\tassertThat(taskExecution.getExitCode()).isEqualTo(exitCode);\n\t\tassertThat(taskExecution.getExternalExecutionId()).isEqualTo(externalExecutionId);\n\t\tassertThat(taskExecution.getParentExecutionId()).isEqualTo(parentExecutionId);\n\n\t\tif (exception != null) {\n\t\t\tassertThat(taskExecution.getErrorMessage().length() > exception.getStackTrace().length).isTrue();\n\t\t}\n\t\telse {\n\t\t\tassertThat(taskExecution.getExitMessage()).isNull();\n\t\t}\n\n\t\tif (update) {\n\t\t\tassertThat(taskExecution.getEndTime().isAfter(taskExecution.getStartTime())\n\t\t\t\t\t|| taskExecution.getEndTime().isEqual(taskExecution.getStartTime()))\n\t\t\t\t.isTrue();\n\t\t\tassertThat(taskExecution.getExitCode()).isNotNull();\n\t\t}\n\t\telse {\n\t\t\tassertThat(taskExecution.getEndTime()).isNull();\n\t\t\tassertThat(taskExecution.getExitCode() == null).isTrue();\n\t\t}\n\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"testTask\");\n\t}\n\n\t@Configuration\n\tpublic static class ArgsConfiguration {\n\n\t\t@Bean\n\t\tpublic ApplicationArguments args() {\n\t\t\tMap<String, String> args = new HashMap<>(2);\n\n\t\t\targs.put(\"foo\", \"bar\");\n\t\t\targs.put(\"baz\", \"qux\");\n\n\t\t\treturn new SimpleApplicationArgs(args);\n\t\t}\n\n\t}\n\n\tprivate static class SimpleApplicationArgs implements ApplicationArguments {\n\n\t\tprivate Map<String, String> args;\n\n\t\tSimpleApplicationArgs(Map<String, String> args) {\n\t\t\tthis.args = args;\n\t\t}\n\n\t\t@Override\n\t\tpublic String[] getSourceArgs() {\n\t\t\tString[] sourceArgs = new String[this.args.size()];\n\n\t\t\tint i = 0;\n\t\t\tfor (Map.Entry<String, String> stringStringEntry : this.args.entrySet()) {\n\t\t\t\tsourceArgs[i] = \"--\" + stringStringEntry.getKey() + \"=\" + stringStringEntry.getValue();\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\treturn sourceArgs;\n\t\t}\n\n\t\t@Override\n\t\tpublic Set<String> getOptionNames() {\n\t\t\treturn this.args.keySet();\n\t\t}\n\n\t\t@Override\n\t\tpublic boolean containsOption(String s) {\n\t\t\treturn this.args.containsKey(s);\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> getOptionValues(String s) {\n\t\t\treturn Collections.singletonList(this.args.get(s));\n\t\t}\n\n\t\t@Override\n\t\tpublic List<String> getNonOptionArgs() {\n\t\t\tthrow new UnsupportedOperationException(\"Not supported at this time.\");\n\t\t}\n\n\t}\n\n\tprivate static final class TestListener2 extends TestListener {\n\n\t}\n\n\tprivate static class TestListener implements TaskExecutionListener {\n\n\t\tstatic List<Integer> startupOrderList = new ArrayList<>();\n\t\tstatic List<Integer> endOrderList = new ArrayList<>();\n\t\tstatic List<Integer> failOrderList = new ArrayList<>();\n\n\t\tprivate static int currentCount = 0;\n\n\t\tprivate int id = 0;\n\n\t\tTestListener() {\n\t\t\tcurrentCount++;\n\t\t\tthis.id = currentCount;\n\t\t}\n\n\t\tpublic static List<Integer> getStartupOrderList() {\n\t\t\treturn startupOrderList;\n\t\t}\n\n\t\tpublic static List<Integer> getEndOrderList() {\n\t\t\treturn endOrderList;\n\t\t}\n\n\t\tpublic static List<Integer> getFailOrderList() {\n\t\t\treturn failOrderList;\n\t\t}\n\n\t\t@Override\n\t\tpublic void onTaskStartup(TaskExecution taskExecution) {\n\t\t\tstartupOrderList.add(this.id);\n\t\t}\n\n\t\t@Override\n\t\tpublic void onTaskEnd(TaskExecution taskExecution) {\n\t\t\tendOrderList.add(this.id);\n\t\t}\n\n\t\t@Override\n\t\tpublic void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {\n\t\t\tfailOrderList.add(this.id);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskListenerExecutorObjectFactoryTests.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.listener.annotation.AfterTask;\nimport org.springframework.cloud.task.listener.annotation.BeforeTask;\nimport org.springframework.cloud.task.listener.annotation.FailedTask;\nimport org.springframework.cloud.task.listener.annotation.TaskListenerExecutor;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Verifies that the {@link TaskListenerExecutorObjectFactory} retrieves the\n * {@link TaskListenerExecutor}.\n *\n * @author Glenn Renfro\n * @author Isik Erhan\n * @since 2.1.0\n */\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = { TaskListenerExecutorObjectFactoryTests.TaskExecutionListenerConfiguration.class })\n@DirtiesContext\npublic class TaskListenerExecutorObjectFactoryTests {\n\n\t/**\n\t * Task name constant for the Before TaskListener tests.\n\t */\n\tpublic static final String BEFORE_LISTENER = \"BEFORE LISTENER\";\n\n\t/**\n\t * Task name constant for the After TaskListener tests.\n\t */\n\tpublic static final String AFTER_LISTENER = \"AFTER LISTENER\";\n\n\t/**\n\t * Task name constant for the Fail TaskListener tests.\n\t */\n\tpublic static final String FAIL_LISTENER = \"FAIL LISTENER\";\n\n\t/**\n\t * Collection of the task execution listeners that were fired.\n\t */\n\tpublic static List<TaskExecution> taskExecutionListenerResults = new ArrayList<>(3);\n\n\tprivate TaskListenerExecutor taskListenerExecutor;\n\n\tprivate TaskListenerExecutorObjectFactory taskListenerExecutorObjectFactory;\n\n\tpublic void setup(ConfigurableApplicationContext context) {\n\t\ttaskExecutionListenerResults.clear();\n\t\tthis.taskListenerExecutorObjectFactory = new TaskListenerExecutorObjectFactory(context);\n\t\tthis.taskListenerExecutor = this.taskListenerExecutorObjectFactory.getObject();\n\t}\n\n\t@Test\n\tpublic void verifyTaskStartupListener() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskExecutionListenerConfiguration.class);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tsetup(context);\n\n\t\t\tthis.taskListenerExecutor.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER));\n\t\t\tvalidateSingleEntry(BEFORE_LISTENER);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void verifyTaskFailedListener() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskExecutionListenerConfiguration.class);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tsetup(context);\n\n\t\t\tthis.taskListenerExecutor.onTaskFailed(createSampleTaskExecution(FAIL_LISTENER),\n\t\t\t\t\tnew IllegalStateException(\"oops\"));\n\t\t\tvalidateSingleEntry(FAIL_LISTENER);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void verifyTaskEndListener() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskExecutionListenerConfiguration.class);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tsetup(context);\n\n\t\t\tthis.taskListenerExecutor.onTaskEnd(createSampleTaskExecution(AFTER_LISTENER));\n\t\t\tvalidateSingleEntry(AFTER_LISTENER);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void verifyAllListener() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskExecutionListenerConfiguration.class);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tsetup(context);\n\n\t\t\tthis.taskListenerExecutor.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER));\n\t\t\tthis.taskListenerExecutor.onTaskFailed(createSampleTaskExecution(FAIL_LISTENER),\n\t\t\t\t\tnew IllegalStateException(\"oops\"));\n\t\t\tthis.taskListenerExecutor.onTaskEnd(createSampleTaskExecution(AFTER_LISTENER));\n\t\t\tassertThat(taskExecutionListenerResults.size()).isEqualTo(3);\n\t\t\tassertThat(taskExecutionListenerResults.get(0).getTaskName()).isEqualTo(BEFORE_LISTENER);\n\t\t\tassertThat(taskExecutionListenerResults.get(1).getTaskName()).isEqualTo(FAIL_LISTENER);\n\t\t\tassertThat(taskExecutionListenerResults.get(2).getTaskName()).isEqualTo(AFTER_LISTENER);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void verifyTaskStartupListenerWithMultipleInstances() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskExecutionListenerMultipleInstanceConfiguration.class);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tsetup(context);\n\n\t\t\tthis.taskListenerExecutor.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER));\n\t\t\tvalidateSingleEventWithMultipleInstances(BEFORE_LISTENER);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void verifyTaskFailedListenerWithMultipleInstances() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskExecutionListenerMultipleInstanceConfiguration.class);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tsetup(context);\n\n\t\t\tthis.taskListenerExecutor.onTaskFailed(createSampleTaskExecution(FAIL_LISTENER),\n\t\t\t\t\tnew IllegalStateException(\"oops\"));\n\t\t\tvalidateSingleEventWithMultipleInstances(FAIL_LISTENER);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void verifyTaskEndListenerWithMultipleInstances() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskExecutionListenerMultipleInstanceConfiguration.class);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tsetup(context);\n\n\t\t\tthis.taskListenerExecutor.onTaskEnd(createSampleTaskExecution(AFTER_LISTENER));\n\t\t\tvalidateSingleEventWithMultipleInstances(AFTER_LISTENER);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void verifyAllListenerWithMultipleInstances() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TaskExecutionListenerMultipleInstanceConfiguration.class);\n\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tsetup(context);\n\n\t\t\tthis.taskListenerExecutor.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER));\n\t\t\tthis.taskListenerExecutor.onTaskFailed(createSampleTaskExecution(FAIL_LISTENER),\n\t\t\t\t\tnew IllegalStateException(\"oops\"));\n\t\t\tthis.taskListenerExecutor.onTaskEnd(createSampleTaskExecution(AFTER_LISTENER));\n\t\t\tassertThat(taskExecutionListenerResults.size()).isEqualTo(6);\n\t\t\tassertThat(taskExecutionListenerResults.get(0).getTaskName()).isEqualTo(BEFORE_LISTENER);\n\t\t\tassertThat(taskExecutionListenerResults.get(1).getTaskName()).isEqualTo(BEFORE_LISTENER);\n\t\t\tassertThat(taskExecutionListenerResults.get(2).getTaskName()).isEqualTo(FAIL_LISTENER);\n\t\t\tassertThat(taskExecutionListenerResults.get(3).getTaskName()).isEqualTo(FAIL_LISTENER);\n\t\t\tassertThat(taskExecutionListenerResults.get(4).getTaskName()).isEqualTo(AFTER_LISTENER);\n\t\t\tassertThat(taskExecutionListenerResults.get(5).getTaskName()).isEqualTo(AFTER_LISTENER);\n\t\t});\n\t}\n\n\tprivate TaskExecution createSampleTaskExecution(String taskName) {\n\t\tTaskExecution taskExecution = new TaskExecution();\n\t\ttaskExecution.setTaskName(taskName);\n\t\treturn taskExecution;\n\t}\n\n\tprivate void validateSingleEntry(String event) {\n\t\tassertThat(taskExecutionListenerResults.size()).isEqualTo(1);\n\t\tassertThat(taskExecutionListenerResults.get(0).getTaskName()).isEqualTo(event);\n\t}\n\n\tprivate void validateSingleEventWithMultipleInstances(String event) {\n\t\tassertThat(taskExecutionListenerResults.size()).isEqualTo(2);\n\t\tassertThat(taskExecutionListenerResults).allSatisfy(task -> assertThat(task.getTaskName()).isEqualTo(event));\n\t}\n\n\t@Configuration\n\tpublic static class TaskExecutionListenerConfiguration {\n\n\t\t@Bean\n\t\tpublic TaskRunComponent taskRunComponent() {\n\t\t\treturn new TaskRunComponent();\n\t\t}\n\n\t}\n\n\t@Configuration\n\tpublic static class TaskExecutionListenerMultipleInstanceConfiguration {\n\n\t\t@Bean\n\t\tpublic TaskRunComponent taskRunComponent() {\n\t\t\treturn new TaskRunComponent();\n\t\t}\n\n\t\t@Bean\n\t\tpublic TaskRunComponent otherTaskRunComponent() {\n\t\t\treturn new TaskRunComponent();\n\t\t}\n\n\t}\n\n\tpublic static class TaskRunComponent {\n\n\t\t@BeforeTask\n\t\tpublic void initBeforeListener(TaskExecution taskExecution) {\n\t\t\tTaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution);\n\t\t}\n\n\t\t@AfterTask\n\t\tpublic void initAfterListener(TaskExecution taskExecution) {\n\t\t\tTaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution);\n\t\t}\n\n\t\t@FailedTask\n\t\tpublic void initFailedListener(TaskExecution taskExecution, Throwable exception) {\n\t\t\tTaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/micrometer/TaskObservationsTests.java",
    "content": "/*\n * Copyright 2019-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.micrometer;\n\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\n\nimport io.micrometer.core.instrument.LongTaskTimer;\nimport io.micrometer.core.instrument.Tags;\nimport io.micrometer.core.instrument.observation.DefaultMeterObservationHandler;\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport io.micrometer.core.tck.MeterRegistryAssert;\nimport io.micrometer.observation.Observation;\nimport io.micrometer.observation.ObservationHandler;\nimport io.micrometer.observation.ObservationRegistry;\nimport io.micrometer.observation.tck.ObservationRegistryAssert;\nimport io.micrometer.observation.tck.TestObservationRegistry;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.configuration.TaskObservationCloudKeyValues;\nimport org.springframework.cloud.task.listener.TaskExecutionObservation;\nimport org.springframework.cloud.task.listener.TaskObservations;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.cloud.task.listener.TaskObservations.UNKNOWN;\n\n/**\n * @author Christian Tzolov\n * @author Glenn Renfro\n */\npublic class TaskObservationsTests {\n\n\t/**\n\t * Prefix for the spring cloud task project.\n\t */\n\tpublic static final String PREFIX = \"spring.cloud.task\";\n\n\tprivate TaskObservations taskObservations;\n\n\tprivate SimpleMeterRegistry simpleMeterRegistry;\n\n\tprivate ObservationRegistry observationRegistry;\n\n\t@BeforeEach\n\tpublic void before() {\n\t\tthis.simpleMeterRegistry = new SimpleMeterRegistry();\n\t\tthis.observationRegistry = TestObservationRegistry.create();\n\t\tObservationHandler<Observation.Context> timerObservationHandler = new DefaultMeterObservationHandler(\n\t\t\t\tthis.simpleMeterRegistry);\n\t\tthis.observationRegistry.observationConfig().observationHandler(timerObservationHandler);\n\t\tthis.taskObservations = new TaskObservations(this.observationRegistry, null, null);\n\t}\n\n\t@AfterEach\n\tpublic void after() {\n\t\tthis.simpleMeterRegistry.clear();\n\t\tObservationRegistryAssert.assertThat(this.observationRegistry).doesNotHaveAnyRemainingCurrentObservation();\n\t}\n\n\t@Test\n\tpublic void successfulTaskTest() {\n\n\t\tTaskExecution taskExecution = startupObservationForBasicTests(\"myTask72\", 123L);\n\n\t\tLongTaskTimer longTaskTimer = initializeBasicTest(\"myTask72\", \"123\");\n\n\t\t// Finish Task\n\t\ttaskObservations.onTaskEnd(taskExecution);\n\n\t\tverifyDefaultKeyValues();\n\t\tTaskExecutionObservation.TASK_ACTIVE.getDefaultConvention();\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(\"spring.cloud.task\", Tags\n\t\t\t\t.of(TaskExecutionObservation.TaskKeyValues.TASK_STATUS.asString(), TaskObservations.STATUS_SUCCESS));\n\n\t\tverifyLongTaskTimerAfterStop(longTaskTimer, \"myTask72\", \"123\");\n\t}\n\n\t@Test\n\tpublic void defaultTaskTest() {\n\n\t\tTaskExecution taskExecution = new TaskExecution(123L, 0, null, LocalDateTime.now(), LocalDateTime.now(), null,\n\t\t\t\tnew ArrayList<>(), null, null, null);\n\n\t\t// Start Task\n\t\ttaskObservations.onTaskStartup(taskExecution);\n\n\t\tLongTaskTimer longTaskTimer = initializeBasicTest(UNKNOWN, \"123\");\n\n\t\t// Finish Task\n\t\ttaskObservations.onTaskEnd(taskExecution);\n\n\t\t// Test Timer\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_NAME.asString(), UNKNOWN));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.asString(), \"123\"));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_PARENT_EXECUTION_ID.asString(), UNKNOWN));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXTERNAL_EXECUTION_ID.asString(), UNKNOWN));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXIT_CODE.asString(), \"0\"));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX, Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_STATUS.asString(),\n\t\t\t\t\tTaskObservations.STATUS_SUCCESS));\n\n\t\tverifyLongTaskTimerAfterStop(longTaskTimer, \"unknown\", \"123\");\n\n\t}\n\n\t@Test\n\tpublic void failingTask() {\n\n\t\tTaskExecution taskExecution = startupObservationForBasicTests(\"myTask72\", 123L);\n\n\t\tLongTaskTimer longTaskTimer = initializeBasicTest(\"myTask72\", \"123\");\n\n\t\ttaskObservations.onTaskFailed(new RuntimeException(\"Test\"));\n\n\t\t// Finish Task. TaskLifecycleListen calls onTaskEnd after the onTaskFailed. Make\n\t\t// sure that the counter status\n\t\t// is not affected by this.\n\t\ttaskExecution.setExitCode(1);\n\t\ttaskObservations.onTaskEnd(taskExecution);\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_NAME.asString(), \"myTask72\"));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.asString(), \"123\"));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_PARENT_EXECUTION_ID.asString(), \"-1\"));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXIT_CODE.asString(), \"1\"));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX, Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_STATUS.asString(),\n\t\t\t\t\tTaskObservations.STATUS_FAILURE));\n\n\t\tverifyLongTaskTimerAfterStop(longTaskTimer, \"myTask72\", \"123\");\n\t}\n\n\t@Test\n\tpublic void taskWithCloudKeyValues() {\n\t\tfinal String APPLICATION_ID = \"123\";\n\t\tfinal String APPLICATION_NAME = \"APP123\";\n\t\tfinal String SPACE_ID = \"123\";\n\t\tfinal String SPACE_NAME = \"SPACE123\";\n\t\tfinal String APPLICATION_VERSION = \"APPV123\";\n\t\tfinal String INSTANCE_INDEX = \"55\";\n\t\tfinal String ORGANIZATION_NAME = \"ORG123\";\n\t\tTaskObservationCloudKeyValues taskObservationCloudKeyValues = new TaskObservationCloudKeyValues();\n\t\ttaskObservationCloudKeyValues.setApplicationId(APPLICATION_ID);\n\t\ttaskObservationCloudKeyValues.setApplicationName(APPLICATION_NAME);\n\t\ttaskObservationCloudKeyValues.setSpaceId(SPACE_ID);\n\t\ttaskObservationCloudKeyValues.setSpaceName(SPACE_NAME);\n\t\ttaskObservationCloudKeyValues.setApplicationVersion(APPLICATION_VERSION);\n\t\ttaskObservationCloudKeyValues.setInstanceIndex(INSTANCE_INDEX);\n\t\ttaskObservationCloudKeyValues.setOrganizationName(ORGANIZATION_NAME);\n\t\tthis.taskObservations = new TaskObservations(this.observationRegistry, taskObservationCloudKeyValues, null);\n\n\t\tTaskExecution taskExecution = startupObservationForBasicTests(\"myTask72\", 123L);\n\n\t\tLongTaskTimer longTaskTimer = initializeBasicTest(\"myTask72\", \"123\");\n\n\t\t// Finish Task\n\t\ttaskObservations.onTaskEnd(taskExecution);\n\n\t\tverifyDefaultKeyValues();\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_ORG_NAME.asString(), ORGANIZATION_NAME));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_SPACE_ID.asString(), SPACE_ID));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_SPACE_NAME.asString(), SPACE_NAME));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_NAME.asString(), APPLICATION_NAME));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_ID.asString(), APPLICATION_ID));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX, Tags\n\t\t\t\t.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_VERSION.asString(), APPLICATION_VERSION));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_INSTANCE_INDEX.asString(), INSTANCE_INDEX));\n\n\t\t// Test Timer\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_NAME.asString(), \"myTask72\"));\n\n\t\tverifyLongTaskTimerAfterStop(longTaskTimer, \"myTask72\", \"123\");\n\t}\n\n\t@Test\n\tpublic void testCloudVariablesUninitialized() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(CloudConfigurationForDefaultValues.class));\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tTaskObservationCloudKeyValues taskObservationCloudKeyValues = context\n\t\t\t\t.getBean(TaskObservationCloudKeyValues.class);\n\n\t\t\tassertThat(taskObservationCloudKeyValues).as(\"taskObservationCloudKeyValues should not be null\")\n\t\t\t\t.isNotNull();\n\n\t\t\tthis.taskObservations = new TaskObservations(this.observationRegistry, taskObservationCloudKeyValues, null);\n\n\t\t\tTaskExecution taskExecution = startupObservationForBasicTests(\"myTask72\", 123L);\n\n\t\t\tLongTaskTimer longTaskTimer = initializeBasicTest(\"myTask72\", \"123\");\n\n\t\t\t// Finish Task\n\t\t\ttaskObservations.onTaskEnd(taskExecution);\n\n\t\t\tverifyDefaultKeyValues();\n\n\t\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_ORG_NAME.asString(), \"default\"));\n\n\t\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_SPACE_ID.asString(), UNKNOWN));\n\n\t\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_SPACE_NAME.asString(), UNKNOWN));\n\n\t\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_NAME.asString(), UNKNOWN));\n\n\t\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_ID.asString(), UNKNOWN));\n\n\t\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_APP_VERSION.asString(), UNKNOWN));\n\n\t\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_CF_INSTANCE_INDEX.asString(), \"0\"));\n\n\t\t\t// Test Timer\n\t\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_NAME.asString(), \"myTask72\"));\n\n\t\t\tverifyLongTaskTimerAfterStop(longTaskTimer, \"myTask72\", \"123\");\n\t\t});\n\t}\n\n\tprivate TaskExecution startupObservationForBasicTests(String taskName, long taskExecutionId) {\n\t\tTaskExecution taskExecution = new TaskExecution(taskExecutionId, 0, taskName, LocalDateTime.now(),\n\t\t\t\tLocalDateTime.now(), null, new ArrayList<>(), null, \"-1\", -1L);\n\n\t\t// Start Task\n\t\ttaskObservations.onTaskStartup(taskExecution);\n\t\treturn taskExecution;\n\t}\n\n\tprivate LongTaskTimer initializeBasicTest(String taskName, String executionId) {\n\t\t// Test Long Task Timer while the task is running.\n\t\tLongTaskTimer longTaskTimer = simpleMeterRegistry\n\t\t\t.find(TaskExecutionObservation.TASK_ACTIVE.getPrefix() + \".active\")\n\t\t\t.longTaskTimer();\n\t\tSystem.out.println(simpleMeterRegistry.getMetersAsString());\n\t\tassertThat(longTaskTimer).withFailMessage(\"LongTask timer should be created on Task start\").isNotNull();\n\t\tassertThat(longTaskTimer.activeTasks()).isEqualTo(1);\n\t\tassertThat(longTaskTimer.getId().getTag(TaskExecutionObservation.TaskKeyValues.TASK_NAME.asString()))\n\t\t\t.isEqualTo(taskName);\n\t\tassertThat(longTaskTimer.getId().getTag(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.asString()))\n\t\t\t.isEqualTo(executionId);\n\t\treturn longTaskTimer;\n\t}\n\n\tprivate void verifyDefaultKeyValues() {\n\t\t// Test Timer\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_NAME.asString(), \"myTask72\"));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.asString(), \"123\"));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_PARENT_EXECUTION_ID.asString(), \"-1\"));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX,\n\t\t\t\t\tTags.of(TaskExecutionObservation.TaskKeyValues.TASK_EXIT_CODE.asString(), \"0\"));\n\n\t\tMeterRegistryAssert.assertThat(this.simpleMeterRegistry)\n\t\t\t.hasTimerWithNameAndTags(PREFIX, Tags.of(TaskExecutionObservation.TaskKeyValues.TASK_STATUS.asString(),\n\t\t\t\t\tTaskObservations.STATUS_SUCCESS));\n\t}\n\n\tprivate void verifyLongTaskTimerAfterStop(LongTaskTimer longTaskTimer, String taskName, String executionId) {\n\t\t// Test Long Task Timer after the task has completed.\n\t\tassertThat(longTaskTimer.activeTasks()).isEqualTo(0);\n\t\tassertThat(longTaskTimer.getId().getTag(TaskExecutionObservation.TaskKeyValues.TASK_NAME.asString()))\n\t\t\t.isEqualTo(taskName);\n\t\tassertThat(longTaskTimer.getId().getTag(TaskExecutionObservation.TaskKeyValues.TASK_EXECUTION_ID.asString()))\n\t\t\t.isEqualTo(executionId);\n\t}\n\n\t@Configuration\n\tstatic class CloudConfigurationForDefaultValues {\n\n\t\t@Bean\n\t\tpublic TaskObservationCloudKeyValues taskObservationCloudKeyValues() {\n\t\t\treturn new TaskObservationCloudKeyValues();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/H2TaskRepositoryIntegrationTests.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository;\n\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport org.h2.engine.Mode.ModeEnum;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Henning Pöttker\n */\nclass H2TaskRepositoryIntegrationTests {\n\n\t@ParameterizedTest\n\t@EnumSource(ModeEnum.class)\n\tvoid testTaskRepository(ModeEnum mode) {\n\t\tString connectionUrl = String.format(\"jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;MODE=%s\", UUID.randomUUID(), mode);\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(TestConfiguration.class)\n\t\t\t.withBean(DataSource.class, () -> new SimpleDriverDataSource(new org.h2.Driver(), connectionUrl, \"sa\", \"\"));\n\n\t\tapplicationContextRunner.run((context -> {\n\t\t\tTaskExplorer taskExplorer = context.getBean(TaskExplorer.class);\n\t\t\tassertThat(taskExplorer.getTaskExecutionCount()).isOne();\n\t\t}));\n\t}\n\n\t@EnableTask\n\t@ImportAutoConfiguration(SimpleTaskAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/MariaDbTaskRepositoryIntegrationTests.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Tag;\nimport org.junit.jupiter.api.Test;\nimport org.mariadb.jdbc.MariaDbDataSource;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mariadb.MariaDBContainer;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.boot.autoconfigure.ImportAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\nimport org.springframework.test.context.junit.jupiter.SpringJUnitConfig;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@Tag(\"DockerRequired\")\n@Testcontainers\n@SpringJUnitConfig\npublic class MariaDbTaskRepositoryIntegrationTests {\n\n\tprivate static final DockerImageName MARIADB_IMAGE = DockerImageName.parse(\"mariadb:10.9.3\");\n\n\t/**\n\t * Provide a mariadb test container for tests.\n\t */\n\t@Container\n\tpublic static MariaDBContainer mariaDBContainer = new MariaDBContainer(MARIADB_IMAGE);\n\n\t@Test\n\tpublic void testTaskExplorer() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withUserConfiguration(MariaDbTaskRepositoryIntegrationTests.TestConfiguration.class);\n\n\t\tapplicationContextRunner.run((context -> {\n\t\t\tTaskExplorer taskExplorer = context.getBean(TaskExplorer.class);\n\t\t\tassertThat(taskExplorer.getTaskExecutionCount()).isOne();\n\t\t}));\n\t\tapplicationContextRunner.run((context -> {\n\t\t\tTaskExplorer taskExplorer = context.getBean(TaskExplorer.class);\n\t\t\tassertThat(taskExplorer.getTaskExecutionCount()).isEqualTo(2);\n\t\t}));\n\t}\n\n\t@EnableTask\n\t@ImportAutoConfiguration(SimpleTaskAutoConfiguration.class)\n\tstatic class TestConfiguration {\n\n\t\tpublic static boolean firstTime = true;\n\n\t\t@Bean\n\t\tpublic DataSource dataSource() throws Exception {\n\t\t\tMariaDbDataSource datasource = new MariaDbDataSource();\n\t\t\tdatasource.setUrl(mariaDBContainer.getJdbcUrl());\n\t\t\tdatasource.setUser(mariaDBContainer.getUsername());\n\t\t\tdatasource.setPassword(mariaDBContainer.getPassword());\n\t\t\tif (firstTime) {\n\t\t\t\tResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();\n\t\t\t\tdatabasePopulator\n\t\t\t\t\t.addScript(new ClassPathResource(\"/org/springframework/cloud/task/schema-mariadb.sql\"));\n\t\t\t\tdatabasePopulator.execute(datasource);\n\t\t\t\tfirstTime = false;\n\t\t\t}\n\t\t\treturn datasource;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/dao/BaseTaskExecutionDaoTestCases.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.dao;\n\nimport java.time.LocalDateTime;\nimport java.util.List;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.test.annotation.DirtiesContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.fail;\n\n/**\n * Defines test cases that shall be between {@link TaskExecutionDao} tests.\n *\n * @author Gunnar Hillert\n */\npublic abstract class BaseTaskExecutionDaoTestCases {\n\n\tprotected TaskExecutionDao dao;\n\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionsByTaskNamesWithNullParameter() {\n\t\ttry {\n\t\t\tthis.dao.getLatestTaskExecutionsByTaskNames(null);\n\t\t}\n\t\tcatch (IllegalArgumentException e) {\n\t\t\tassertThat(e.getMessage()).isEqualTo(\"At least 1 task name must be provided.\");\n\t\t\treturn;\n\t\t}\n\t\tfail(\"Expected an IllegalArgumentException to be thrown.\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionsByTaskNamesWithEmptyArrayParameter() {\n\t\ttry {\n\t\t\tthis.dao.getLatestTaskExecutionsByTaskNames(new String[0]);\n\t\t}\n\t\tcatch (IllegalArgumentException e) {\n\t\t\tassertThat(e.getMessage()).isEqualTo(\"At least 1 task name must be provided.\");\n\t\t\treturn;\n\t\t}\n\t\tfail(\"Expected an IllegalArgumentException to be thrown.\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionsByTaskNamesWithArrayParametersContainingNullAndEmptyValues() {\n\t\ttry {\n\t\t\tthis.dao.getLatestTaskExecutionsByTaskNames(\"foo\", null, \"bar\", \" \");\n\t\t}\n\t\tcatch (IllegalArgumentException e) {\n\t\t\tassertThat(e.getMessage())\n\t\t\t\t.isEqualTo(\"Task names must not contain any empty elements but 2 of 4 were empty or null.\");\n\t\t\treturn;\n\t\t}\n\t\tfail(\"Expected an IllegalArgumentException to be thrown.\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionsByTaskNamesWithSingleTaskName() {\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tfinal List<TaskExecution> latestTaskExecutions = this.dao.getLatestTaskExecutionsByTaskNames(\"FOO1\");\n\t\tassertThat(latestTaskExecutions.size() == 1)\n\t\t\t.as(\"Expected only 1 taskExecution but got \" + latestTaskExecutions.size())\n\t\t\t.isTrue();\n\n\t\tfinal TaskExecution lastTaskExecution = latestTaskExecutions.get(0);\n\t\tassertThat(lastTaskExecution.getTaskName()).isEqualTo(\"FOO1\");\n\n\t\tassertThat(lastTaskExecution.getStartTime().getYear()).isEqualTo(2015);\n\t\tassertThat(lastTaskExecution.getStartTime().getMonthValue()).isEqualTo(2);\n\t\tassertThat(lastTaskExecution.getStartTime().getDayOfMonth()).isEqualTo(22);\n\t\tassertThat(lastTaskExecution.getStartTime().getHour()).isEqualTo(23);\n\t\tassertThat(lastTaskExecution.getStartTime().getMinute()).isEqualTo(59);\n\t\tassertThat(lastTaskExecution.getStartTime().getSecond()).isEqualTo(0);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionsByTaskNamesWithMultipleTaskNames() {\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tfinal List<TaskExecution> latestTaskExecutions = this.dao.getLatestTaskExecutionsByTaskNames(\"FOO1\", \"FOO3\",\n\t\t\t\t\"FOO4\");\n\t\tassertThat(latestTaskExecutions.size() == 3)\n\t\t\t.as(\"Expected 3 taskExecutions but got \" + latestTaskExecutions.size())\n\t\t\t.isTrue();\n\n\t\tLocalDateTime startDateTime = latestTaskExecutions.get(0).getStartTime();\n\t\tassertThat(startDateTime.getYear()).isEqualTo(2016);\n\t\tassertThat(startDateTime.getMonthValue()).isEqualTo(8);\n\t\tassertThat(startDateTime.getDayOfMonth()).isEqualTo(20);\n\t\tassertThat(startDateTime.getHour()).isEqualTo(14);\n\t\tassertThat(startDateTime.getMinute()).isEqualTo(45);\n\t\tassertThat(startDateTime.getSecond()).isEqualTo(0);\n\n\t\tLocalDateTime startDateTimeOne = latestTaskExecutions.get(1).getStartTime();\n\n\t\tassertThat(startDateTimeOne.getYear()).isEqualTo(2015);\n\t\tassertThat(startDateTimeOne.getMonthValue()).isEqualTo(2);\n\t\tassertThat(startDateTimeOne.getDayOfMonth()).isEqualTo(22);\n\t\tassertThat(startDateTimeOne.getHour()).isEqualTo(23);\n\t\tassertThat(startDateTimeOne.getMinute()).isEqualTo(59);\n\t\tassertThat(startDateTimeOne.getSecond()).isEqualTo(0);\n\n\t\tLocalDateTime startDateTimeTwo = latestTaskExecutions.get(2).getStartTime();\n\n\t\tassertThat(startDateTimeTwo.getYear()).isEqualTo(2015);\n\t\tassertThat(startDateTimeTwo.getMonthValue()).isEqualTo(2);\n\t\tassertThat(startDateTimeTwo.getDayOfMonth()).isEqualTo(20);\n\t\tassertThat(startDateTimeTwo.getHour()).isEqualTo(14);\n\t\tassertThat(startDateTimeTwo.getMinute()).isEqualTo(45);\n\t\tassertThat(startDateTimeTwo.getSecond()).isEqualTo(0);\n\t}\n\n\t/**\n\t * This test is a special use-case. While not common, it is theoretically possible,\n\t * that a task may have executed with the exact same start time multiple times. In\n\t * that case we should still only get 1 returned {@link TaskExecution}.\n\t */\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionsByTaskNamesWithIdenticalTaskExecutions() {\n\t\tlong executionIdOffset = initializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tfinal List<TaskExecution> latestTaskExecutions = this.dao.getLatestTaskExecutionsByTaskNames(\"FOO5\");\n\t\tassertThat(latestTaskExecutions.size() == 1)\n\t\t\t.as(\"Expected only 1 taskExecution but got \" + latestTaskExecutions.size())\n\t\t\t.isTrue();\n\n\t\tLocalDateTime startDateTime = latestTaskExecutions.get(0).getStartTime();\n\n\t\tassertThat(startDateTime.getYear()).isEqualTo(2015);\n\t\tassertThat(startDateTime.getMonthValue()).isEqualTo(2);\n\t\tassertThat(startDateTime.getDayOfMonth()).isEqualTo(22);\n\t\tassertThat(startDateTime.getHour()).isEqualTo(23);\n\t\tassertThat(startDateTime.getMinute()).isEqualTo(59);\n\t\tassertThat(startDateTime.getSecond()).isEqualTo(0);\n\t\tassertThat(latestTaskExecutions.get(0).getExecutionId()).isEqualTo(9 + executionIdOffset);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionForTaskNameWithNullParameter() {\n\t\ttry {\n\t\t\tthis.dao.getLatestTaskExecutionForTaskName(null);\n\t\t}\n\t\tcatch (IllegalArgumentException e) {\n\t\t\tassertThat(e.getMessage()).isEqualTo(\"The task name must not be empty.\");\n\t\t\treturn;\n\t\t}\n\t\tfail(\"Expected an IllegalArgumentException to be thrown.\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionForTaskNameWithEmptyStringParameter() {\n\t\ttry {\n\t\t\tthis.dao.getLatestTaskExecutionForTaskName(\"\");\n\t\t}\n\t\tcatch (IllegalArgumentException e) {\n\t\t\tassertThat(e.getMessage()).isEqualTo(\"The task name must not be empty.\");\n\t\t\treturn;\n\t\t}\n\t\tfail(\"Expected an IllegalArgumentException to be thrown.\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionForNonExistingTaskName() {\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tfinal TaskExecution latestTaskExecution = this.dao.getLatestTaskExecutionForTaskName(\"Bar5\");\n\t\tassertThat(latestTaskExecution).as(\"Expected the latestTaskExecution to be null but got\" + latestTaskExecution)\n\t\t\t.isNull();\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionForExistingTaskName() {\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tfinal TaskExecution latestTaskExecution = this.dao.getLatestTaskExecutionForTaskName(\"FOO1\");\n\t\tassertThat(latestTaskExecution).as(\"Expected the latestTaskExecution not to be null\").isNotNull();\n\n\t\tLocalDateTime startDateTime = latestTaskExecution.getStartTime();\n\n\t\tassertThat(startDateTime.getYear()).isEqualTo(2015);\n\t\tassertThat(startDateTime.getMonthValue()).isEqualTo(2);\n\t\tassertThat(startDateTime.getDayOfMonth()).isEqualTo(22);\n\t\tassertThat(startDateTime.getHour()).isEqualTo(23);\n\t\tassertThat(startDateTime.getMinute()).isEqualTo(59);\n\t\tassertThat(startDateTime.getSecond()).isEqualTo(0);\n\t}\n\n\t/**\n\t * This test is a special use-case. While not common, it is theoretically possible,\n\t * that a task may have executed with the exact same start time multiple times. In\n\t * that case we should still only get 1 returned {@link TaskExecution}.\n\t */\n\t@Test\n\t@DirtiesContext\n\tpublic void getLatestTaskExecutionForTaskNameWithIdenticalTaskExecutions() {\n\t\tlong executionIdOffset = initializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tfinal TaskExecution latestTaskExecution = this.dao.getLatestTaskExecutionForTaskName(\"FOO5\");\n\t\tassertThat(latestTaskExecution).as(\"Expected the latestTaskExecution not to be null\").isNotNull();\n\n\t\tLocalDateTime startDateTime = latestTaskExecution.getStartTime();\n\n\t\tassertThat(startDateTime.getYear()).isEqualTo(2015);\n\t\tassertThat(startDateTime.getMonthValue()).isEqualTo(2);\n\t\tassertThat(startDateTime.getDayOfMonth()).isEqualTo(22);\n\t\tassertThat(startDateTime.getHour()).isEqualTo(23);\n\t\tassertThat(startDateTime.getMinute()).isEqualTo(59);\n\t\tassertThat(startDateTime.getSecond()).isEqualTo(0);\n\t\tassertThat(latestTaskExecution.getExecutionId()).isEqualTo(9 + executionIdOffset);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void getRunningTaskExecutions() {\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tassertThat(this.dao.getRunningTaskExecutionCount()).isEqualTo(this.dao.getTaskExecutionCount());\n\t\tthis.dao.completeTaskExecution(1, 0, LocalDateTime.now(), \"c'est fini!\");\n\t\tassertThat(this.dao.getRunningTaskExecutionCount()).isEqualTo(this.dao.getTaskExecutionCount() - 1);\n\t}\n\n\tprotected long initializeRepositoryNotInOrderWithMultipleTaskExecutions() {\n\n\t\tfinal TaskExecution foo1_0 = getTaskExecution(\"FOO1\", \"externalC\");\n\t\tfoo1_0.setStartTime(getDate(2015, 2, 22, 23, 59));\n\n\t\tfinal TaskExecution foo1_1 = getTaskExecution(\"FOO1\", \"externalC\");\n\t\tfoo1_1.setStartTime(getDate(2015, 2, 20, 14, 45));\n\n\t\tfinal TaskExecution foo1_2 = getTaskExecution(\"FOO1\", \"externalC\");\n\t\tfoo1_2.setStartTime(getDate(2015, 1, 19, 14, 30));\n\n\t\tfinal TaskExecution foo1_3 = getTaskExecution(\"FOO1\", \"externalC\");\n\t\tfoo1_3.setStartTime(getDate(2015, 1, 20, 14, 45));\n\n\t\tTaskExecution foo2 = getTaskExecution(\"FOO2\", \"externalA\");\n\t\tfoo2.setStartTime(getDate(2015, 4, 20, 14, 45));\n\n\t\tTaskExecution foo3 = getTaskExecution(\"FOO3\", \"externalB\");\n\t\tfoo3.setStartTime(getDate(2016, 8, 20, 14, 45));\n\n\t\tTaskExecution foo4 = getTaskExecution(\"FOO4\", \"externalB\");\n\t\tfoo4.setStartTime(getDate(2015, 2, 20, 14, 45));\n\n\t\tfinal TaskExecution foo5_0 = getTaskExecution(\"FOO5\", \"externalC\");\n\t\tfoo5_0.setStartTime(getDate(2015, 2, 22, 23, 59));\n\n\t\tfinal TaskExecution foo5_1 = getTaskExecution(\"FOO5\", \"externalC\");\n\t\tfoo5_1.setStartTime(getDate(2015, 2, 22, 23, 59));\n\n\t\tfinal TaskExecution foo5_2 = getTaskExecution(\"FOO5\", \"externalC\");\n\t\tfoo5_2.setStartTime(getDate(2015, 2, 22, 23, 59));\n\n\t\tlong executionIdOffset = this.createTaskExecution(foo1_0);\n\t\tthis.createTaskExecution(foo1_1);\n\t\tthis.createTaskExecution(foo1_2);\n\t\tthis.createTaskExecution(foo1_3);\n\n\t\tthis.createTaskExecution(foo2);\n\t\tthis.createTaskExecution(foo3);\n\t\tthis.createTaskExecution(foo4);\n\n\t\tthis.createTaskExecution(foo5_0);\n\t\tthis.createTaskExecution(foo5_1);\n\t\tthis.createTaskExecution(foo5_2);\n\n\t\treturn executionIdOffset;\n\t}\n\n\tprivate LocalDateTime getDate(int year, int month, int day, int hour, int minute) {\n\t\treturn LocalDateTime.now()\n\t\t\t.withYear(year)\n\t\t\t.withMonth(month)\n\t\t\t.withDayOfMonth(day)\n\t\t\t.withHour(hour)\n\t\t\t.withMinute(minute)\n\t\t\t.withSecond(0);\n\t}\n\n\tprivate long createTaskExecution(TaskExecution te) {\n\t\treturn this.dao\n\t\t\t.createTaskExecution(te.getTaskName(), te.getStartTime(), te.getArguments(), te.getExternalExecutionId())\n\t\t\t.getExecutionId();\n\t}\n\n\tprotected TaskExecution getTaskExecution(String taskName, String externalExecutionId) {\n\t\tTaskExecution taskExecution = new TaskExecution();\n\t\ttaskExecution.setTaskName(taskName);\n\t\ttaskExecution.setExternalExecutionId(externalExecutionId);\n\t\ttaskExecution.setStartTime(LocalDateTime.now());\n\t\treturn taskExecution;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/dao/JdbcTaskExecutionDaoMariaDBIntegrationTests.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.dao;\n\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Tag;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.mariadb.jdbc.MariaDbDataSource;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mariadb.MariaDBContainer;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.cloud.task.configuration.TestConfiguration;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.util.TestDBUtils;\nimport org.springframework.cloud.task.util.TestVerifierUtils;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatThrownBy;\n\n/**\n * Executes unit integration tests on JdbcTaskExecutionDao for MARIADB.\n *\n * @author Glenn Renfro\n */\n@Tag(\"DockerRequired\")\n@Testcontainers\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = { TestConfiguration.class,\n\t\tJdbcTaskExecutionDaoMariaDBIntegrationTests.TestDataSourceConfiguration.class,\n\t\tPropertyPlaceholderAutoConfiguration.class })\npublic class JdbcTaskExecutionDaoMariaDBIntegrationTests extends BaseTaskExecutionDaoTestCases {\n\n\tprivate static final DockerImageName MARIADB_IMAGE = DockerImageName.parse(\"mariadb:10.9.3\");\n\n\t/**\n\t * Provide mariadb test container for tests.\n\t */\n\t@Container\n\tpublic static MariaDBContainer mariaDBContainer = new MariaDBContainer(MARIADB_IMAGE);\n\n\t@Autowired\n\tTaskRepository repository;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@BeforeEach\n\tpublic void setup() {\n\t\tfinal JdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(this.dataSource);\n\t\tdao.setTaskIncrementer(TestDBUtils.getIncrementer(this.dataSource));\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\tjdbcTemplate.execute(\"TRUNCATE TABLE TASK_EXECUTION_PARAMS\");\n\t\tjdbcTemplate.execute(\"DELETE FROM TASK_EXECUTION\");\n\t\tjdbcTemplate.execute(\"ALTER SEQUENCE TASK_SEQ RESTART;\");\n\t\tsuper.dao = dao;\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testStartTaskExecution() {\n\t\tTaskExecution expectedTaskExecution = this.dao.createTaskExecution(null, null, new ArrayList<>(0), null);\n\n\t\texpectedTaskExecution.setArguments(Collections.singletonList(\"foo=\" + UUID.randomUUID().toString()));\n\t\texpectedTaskExecution.setStartTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setTaskName(UUID.randomUUID().toString());\n\n\t\tthis.dao.startTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tTestDBUtils.getTaskExecutionFromDB(this.dataSource, expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void createTaskExecution() {\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.createSampleTaskExecutionNoArg();\n\t\texpectedTaskExecution = this.dao.createTaskExecution(expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tTestDBUtils.getTaskExecutionFromDB(this.dataSource, expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void createEmptyTaskExecution() {\n\t\tTaskExecution expectedTaskExecution = this.dao.createTaskExecution(null, null, new ArrayList<>(0), null);\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tTestDBUtils.getTaskExecutionFromDB(this.dataSource, expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void completeTaskExecution() {\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.endSampleTaskExecutionNoArg();\n\t\texpectedTaskExecution = this.dao.createTaskExecution(expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\t\tthis.dao.completeTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getExitCode(),\n\t\t\t\texpectedTaskExecution.getEndTime(), expectedTaskExecution.getExitMessage());\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tTestDBUtils.getTaskExecutionFromDB(this.dataSource, expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void completeTaskExecutionWithNoCreate() {\n\t\tJdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(this.dataSource);\n\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.endSampleTaskExecutionNoArg();\n\t\tassertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> {\n\t\t\tdao.completeTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getExitCode(),\n\t\t\t\t\texpectedTaskExecution.getEndTime(), expectedTaskExecution.getExitMessage());\n\t\t});\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testFindAllPageableSort() {\n\t\tinitializeRepositoryNotInOrder();\n\t\tSort sort = Sort.by(new Sort.Order(Sort.Direction.ASC, \"EXTERNAL_EXECUTION_ID\"));\n\t\tIterator<TaskExecution> iter = getPageIterator(0, 2, sort);\n\t\tTaskExecution taskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO2\");\n\t\ttaskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO3\");\n\n\t\titer = getPageIterator(1, 2, sort);\n\t\ttaskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO1\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testFindAllDefaultSort() {\n\t\tinitializeRepository();\n\t\tIterator<TaskExecution> iter = getPageIterator(0, 2, null);\n\t\tTaskExecution taskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO1\");\n\t\ttaskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO2\");\n\n\t\titer = getPageIterator(1, 2, null);\n\t\ttaskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO3\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testStartExecutionWithNullExternalExecutionIdExisting() {\n\t\tTaskExecution expectedTaskExecution = initializeTaskExecutionWithExternalExecutionId();\n\n\t\tthis.dao.startTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(), null);\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tTestDBUtils.getTaskExecutionFromDB(this.dataSource, expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testStartExecutionWithNullExternalExecutionIdNonExisting() {\n\t\tTaskExecution expectedTaskExecution = initializeTaskExecutionWithExternalExecutionId();\n\n\t\tthis.dao.startTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(), \"BAR\");\n\t\texpectedTaskExecution.setExternalExecutionId(\"BAR\");\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tTestDBUtils.getTaskExecutionFromDB(this.dataSource, expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testFindRunningTaskExecutions() {\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tassertThat(\n\t\t\t\tthis.dao.findRunningTaskExecutions(\"FOO1\", PageRequest.of(1, Integer.MAX_VALUE, Sort.by(\"START_TIME\")))\n\t\t\t\t\t.getTotalElements())\n\t\t\t.isEqualTo(4);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testFindRunningTaskExecutionsIllegalSort() {\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tassertThatThrownBy(() -> this.dao\n\t\t\t.findRunningTaskExecutions(\"FOO1\", PageRequest.of(1, Integer.MAX_VALUE, Sort.by(\"ILLEGAL_SORT\")))\n\t\t\t.getTotalElements()).isInstanceOf(IllegalArgumentException.class)\n\t\t\t.hasMessage(\"Invalid sort option selected: ILLEGAL_SORT\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testFindRunningTaskExecutionsSortWithDifferentCase() {\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tassertThat(\n\t\t\t\tthis.dao.findRunningTaskExecutions(\"FOO1\", PageRequest.of(1, Integer.MAX_VALUE, Sort.by(\"StArT_TiMe\")))\n\t\t\t\t\t.getTotalElements())\n\t\t\t.isEqualTo(4);\n\t}\n\n\tprivate TaskExecution initializeTaskExecutionWithExternalExecutionId() {\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.createSampleTaskExecutionNoArg();\n\t\treturn this.dao.createTaskExecution(expectedTaskExecution.getTaskName(), expectedTaskExecution.getStartTime(),\n\t\t\t\texpectedTaskExecution.getArguments(), \"FOO1\");\n\t}\n\n\tprivate Iterator<TaskExecution> getPageIterator(int pageNum, int pageSize, Sort sort) {\n\t\tPageable pageable = (sort == null) ? PageRequest.of(pageNum, pageSize)\n\t\t\t\t: PageRequest.of(pageNum, pageSize, sort);\n\t\tPage<TaskExecution> page = this.dao.findAll(pageable);\n\t\tassertThat(page.getTotalElements()).isEqualTo(3);\n\t\tassertThat(page.getTotalPages()).isEqualTo(2);\n\t\treturn page.iterator();\n\t}\n\n\tprivate void initializeRepository() {\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO3\", \"externalA\"));\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO2\", \"externalB\"));\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO1\", \"externalC\"));\n\t}\n\n\tprivate void initializeRepositoryNotInOrder() {\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO1\", \"externalC\"));\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO2\", \"externalA\"));\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO3\", \"externalB\"));\n\t}\n\n\t@Configuration\n\tstatic class TestDataSourceConfiguration {\n\n\t\tpublic static boolean firstTime = true;\n\n\t\t@Bean\n\t\tpublic DataSource dataSource() throws Exception {\n\t\t\tMariaDbDataSource datasource = new MariaDbDataSource();\n\t\t\tdatasource.setUrl(mariaDBContainer.getJdbcUrl());\n\t\t\tdatasource.setUser(mariaDBContainer.getUsername());\n\t\t\tdatasource.setPassword(mariaDBContainer.getPassword());\n\t\t\tif (firstTime) {\n\t\t\t\tResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();\n\t\t\t\tdatabasePopulator\n\t\t\t\t\t.addScript(new ClassPathResource(\"/org/springframework/cloud/task/schema-mariadb.sql\"));\n\t\t\t\tdatabasePopulator.execute(datasource);\n\t\t\t\tfirstTime = false;\n\t\t\t}\n\t\t\treturn datasource;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/dao/TaskExecutionDaoTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.dao;\n\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.ValueSource;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.cloud.task.configuration.TestConfiguration;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.util.TestDBUtils;\nimport org.springframework.cloud.task.util.TestVerifierUtils;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.assertj.core.api.Assertions.assertThatThrownBy;\n\n/**\n * Executes unit tests on JdbcTaskExecutionDao.\n *\n * @author Glenn Renfro\n * @author Gunnar Hillert\n * @author Michael Minella\n */\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = { TestConfiguration.class, EmbeddedDataSourceConfiguration.class,\n\t\tPropertyPlaceholderAutoConfiguration.class })\npublic class TaskExecutionDaoTests extends BaseTaskExecutionDaoTestCases {\n\n\t@Autowired\n\tTaskRepository repository;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@BeforeEach\n\tpublic void setup() {\n\t\tfinal JdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(this.dataSource);\n\t\tdao.setTaskIncrementer(TestDBUtils.getIncrementer(this.dataSource));\n\t\tsuper.dao = dao;\n\t}\n\n\t@ParameterizedTest\n\t@DirtiesContext\n\t@ValueSource(strings = { \"db\", \"map\" })\n\tpublic void testStartTaskExecutionGeneric(String testType) {\n\t\tgetDao(testType);\n\t\tTaskExecution expectedTaskExecution = this.dao.createTaskExecution(null, null, new ArrayList<>(0), null);\n\n\t\texpectedTaskExecution.setArguments(Collections.singletonList(\"foo=\" + UUID.randomUUID().toString()));\n\t\texpectedTaskExecution.setStartTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setTaskName(UUID.randomUUID().toString());\n\n\t\tthis.dao.startTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, getTaskExecution(testType, expectedTaskExecution));\n\t}\n\n\tprivate TaskExecutionDao getDao(String type) {\n\t\tif (type.equals(\"db\")) {\n\t\t\tfinal JdbcTaskExecutionDao jdbcDao = new JdbcTaskExecutionDao(this.dataSource);\n\t\t\tjdbcDao.setTaskIncrementer(TestDBUtils.getIncrementer(this.dataSource));\n\t\t\tthis.dao = jdbcDao;\n\t\t}\n\t\telse {\n\t\t\tthis.dao = new MapTaskExecutionDao();\n\t\t}\n\t\treturn this.dao;\n\n\t}\n\n\tprivate TaskExecution getTaskExecution(String type, TaskExecution expectedTaskExecution) {\n\t\tTaskExecution taskExecution;\n\t\tif (type.equals(\"db\")) {\n\t\t\ttaskExecution = TestDBUtils.getTaskExecutionFromDB(this.dataSource, expectedTaskExecution.getExecutionId());\n\t\t}\n\t\telse {\n\t\t\tMap<Long, TaskExecution> taskExecutionMap = ((MapTaskExecutionDao) dao).getTaskExecutions();\n\n\t\t\ttaskExecution = taskExecutionMap.get(expectedTaskExecution.getExecutionId());\n\t\t}\n\t\treturn taskExecution;\n\n\t}\n\n\t@ParameterizedTest\n\t@DirtiesContext\n\t@ValueSource(strings = { \"db\", \"map\" })\n\tpublic void createTaskExecution(String testType) {\n\t\tgetDao(testType);\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.createSampleTaskExecutionNoArg();\n\t\texpectedTaskExecution = this.dao.createTaskExecution(expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, getTaskExecution(testType, expectedTaskExecution));\n\t}\n\n\t@ParameterizedTest\n\t@DirtiesContext\n\t@ValueSource(strings = { \"db\", \"map\" })\n\tpublic void createEmptyTaskExecution(String testType) {\n\t\tgetDao(testType);\n\t\tTaskExecution expectedTaskExecution = this.dao.createTaskExecution(null, null, new ArrayList<>(0), null);\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, getTaskExecution(testType, expectedTaskExecution));\n\t}\n\n\t@ParameterizedTest\n\t@DirtiesContext\n\t@ValueSource(strings = { \"db\", \"map\" })\n\tpublic void completeTaskExecution(String testType) {\n\t\tgetDao(testType);\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.endSampleTaskExecutionNoArg();\n\t\texpectedTaskExecution = this.dao.createTaskExecution(expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\t\tthis.dao.completeTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getExitCode(),\n\t\t\t\texpectedTaskExecution.getEndTime(), expectedTaskExecution.getExitMessage());\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, getTaskExecution(testType, expectedTaskExecution));\n\t}\n\n\t@ParameterizedTest\n\t@DirtiesContext\n\t@ValueSource(strings = { \"db\", \"map\" })\n\tpublic void completeTaskExecutionWithNoCreate(String testType) {\n\t\tgetDao(testType);\n\t\tJdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(this.dataSource);\n\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.endSampleTaskExecutionNoArg();\n\t\tassertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> {\n\t\t\tdao.completeTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getExitCode(),\n\t\t\t\t\texpectedTaskExecution.getEndTime(), expectedTaskExecution.getExitMessage());\n\t\t});\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testFindAllPageableSort() {\n\t\tinitializeRepositoryNotInOrder();\n\t\tSort sort = Sort.by(new Sort.Order(Sort.Direction.ASC, \"EXTERNAL_EXECUTION_ID\"));\n\t\tIterator<TaskExecution> iter = getPageIterator(0, 2, sort);\n\t\tTaskExecution taskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO2\");\n\t\ttaskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO3\");\n\n\t\titer = getPageIterator(1, 2, sort);\n\t\ttaskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO1\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testFindAllDefaultSort() {\n\t\tinitializeRepository();\n\t\tIterator<TaskExecution> iter = getPageIterator(0, 2, null);\n\t\tTaskExecution taskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO1\");\n\t\ttaskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO2\");\n\n\t\titer = getPageIterator(1, 2, null);\n\t\ttaskExecution = iter.next();\n\t\tassertThat(taskExecution.getTaskName()).isEqualTo(\"FOO3\");\n\t}\n\n\t@ParameterizedTest\n\t@DirtiesContext\n\t@ValueSource(strings = { \"db\", \"map\" })\n\tpublic void testStartExecutionWithNullExternalExecutionIdExisting(String testType) {\n\t\tgetDao(testType);\n\t\tTaskExecution expectedTaskExecution = initializeTaskExecutionWithExternalExecutionId();\n\n\t\tthis.dao.startTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(), null);\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, getTaskExecution(testType, expectedTaskExecution));\n\t}\n\n\t@ParameterizedTest\n\t@DirtiesContext\n\t@ValueSource(strings = { \"db\", \"map\" })\n\tpublic void testStartExecutionWithNullExternalExecutionIdNonExisting(String testType) {\n\t\tgetDao(testType);\n\t\tTaskExecution expectedTaskExecution = initializeTaskExecutionWithExternalExecutionId();\n\n\t\tthis.dao.startTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(), \"BAR\");\n\t\texpectedTaskExecution.setExternalExecutionId(\"BAR\");\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, getTaskExecution(testType, expectedTaskExecution));\n\t}\n\n\t@ParameterizedTest\n\t@DirtiesContext\n\t@ValueSource(strings = { \"db\", \"map\" })\n\tpublic void testFindRunningTaskExecutions(String testType) {\n\t\tgetDao(testType);\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tassertThat(this.dao.findRunningTaskExecutions(\"FOO1\", PageRequest.of(1, 4, Sort.by(\"START_TIME\")))\n\t\t\t.getTotalElements()).isEqualTo(4);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testFindRunningTaskExecutionsIllegalSort() {\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tassertThatThrownBy(() -> this.dao\n\t\t\t.findRunningTaskExecutions(\"FOO1\", PageRequest.of(1, Integer.MAX_VALUE, Sort.by(\"ILLEGAL_SORT\")))\n\t\t\t.getTotalElements()).isInstanceOf(IllegalArgumentException.class)\n\t\t\t.hasMessage(\"Invalid sort option selected: ILLEGAL_SORT\");\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testFindRunningTaskExecutionsSortWithDifferentCase() {\n\t\tinitializeRepositoryNotInOrderWithMultipleTaskExecutions();\n\t\tassertThat(\n\t\t\t\tthis.dao.findRunningTaskExecutions(\"FOO1\", PageRequest.of(1, Integer.MAX_VALUE, Sort.by(\"StArT_TiMe\")))\n\t\t\t\t\t.getTotalElements())\n\t\t\t.isEqualTo(4);\n\t}\n\n\tprivate TaskExecution initializeTaskExecutionWithExternalExecutionId() {\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.createSampleTaskExecutionNoArg();\n\t\treturn this.dao.createTaskExecution(expectedTaskExecution.getTaskName(), expectedTaskExecution.getStartTime(),\n\t\t\t\texpectedTaskExecution.getArguments(), \"FOO1\");\n\t}\n\n\tprivate Iterator<TaskExecution> getPageIterator(int pageNum, int pageSize, Sort sort) {\n\t\tPageable pageable = (sort == null) ? PageRequest.of(pageNum, pageSize)\n\t\t\t\t: PageRequest.of(pageNum, pageSize, sort);\n\t\tPage<TaskExecution> page = this.dao.findAll(pageable);\n\t\tassertThat(page.getTotalElements()).isEqualTo(3);\n\t\tassertThat(page.getTotalPages()).isEqualTo(2);\n\t\treturn page.iterator();\n\t}\n\n\tprivate void initializeRepository() {\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO3\", \"externalA\"));\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO2\", \"externalB\"));\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO1\", \"externalC\"));\n\t}\n\n\tprivate void initializeRepositoryNotInOrder() {\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO1\", \"externalC\"));\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO2\", \"externalA\"));\n\t\tthis.repository.createTaskExecution(getTaskExecution(\"FOO3\", \"externalB\"));\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/FindAllPagingQueryProviderTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.cloud.task.util.TestDBUtils;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n * @author Ryan DCruz\n */\npublic class FindAllPagingQueryProviderTests {\n\n\tprivate Pageable pageable = PageRequest.of(0, 10);\n\n\tpublic static Collection<Object[]> data() {\n\t\treturn Arrays.asList(new Object[][] { { \"Oracle\", \"SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, \"\n\t\t\t\t+ \"EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM \"\n\t\t\t\t+ \"(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, \"\n\t\t\t\t+ \"EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID, ROWNUM as \"\n\t\t\t\t+ \"TMP_ROW_NUM FROM (SELECT TASK_EXECUTION_ID, START_TIME, \"\n\t\t\t\t+ \"END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID \"\n\t\t\t\t+ \"FROM %PREFIX%EXECUTION ORDER BY START_TIME DESC, \"\n\t\t\t\t+ \"TASK_EXECUTION_ID DESC)) WHERE TMP_ROW_NUM >= 1 AND \" + \"TMP_ROW_NUM < 11\" },\n\t\t\t\t{ \"HSQL Database Engine\", \"SELECT LIMIT 0 10 TASK_EXECUTION_ID, \"\n\t\t\t\t\t\t+ \"START_TIME, END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, \"\n\t\t\t\t\t\t+ \"ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM %PREFIX%EXECUTION ORDER BY \"\n\t\t\t\t\t\t+ \"START_TIME DESC, TASK_EXECUTION_ID DESC\" },\n\t\t\t\t{ \"PostgreSQL\", \"SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, \"\n\t\t\t\t\t\t+ \"TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID \"\n\t\t\t\t\t\t+ \"FROM %PREFIX%EXECUTION ORDER BY START_TIME DESC, \"\n\t\t\t\t\t\t+ \"TASK_EXECUTION_ID DESC LIMIT 10 OFFSET 0\" },\n\t\t\t\t{ \"MySQL\", \"SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, \"\n\t\t\t\t\t\t+ \"EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM \"\n\t\t\t\t\t\t+ \"%PREFIX%EXECUTION ORDER BY START_TIME DESC, \" + \"TASK_EXECUTION_ID DESC LIMIT 0, 10\" },\n\t\t\t\t{ \"Microsoft SQL Server\", \"SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, \"\n\t\t\t\t\t\t+ \"TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM \"\n\t\t\t\t\t\t+ \"(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, \"\n\t\t\t\t\t\t+ \"EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID, ROW_NUMBER() \"\n\t\t\t\t\t\t+ \"OVER (ORDER BY START_TIME DESC, TASK_EXECUTION_ID DESC) AS \"\n\t\t\t\t\t\t+ \"TMP_ROW_NUM  FROM %PREFIX%EXECUTION) TASK_EXECUTION_PAGE  \"\n\t\t\t\t\t\t+ \"WHERE TMP_ROW_NUM >= 1 AND TMP_ROW_NUM < 11 ORDER BY START_TIME DESC, \"\n\t\t\t\t\t\t+ \"TASK_EXECUTION_ID DESC\" },\n\t\t\t\t{ \"DB2/Linux\", \"SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, \"\n\t\t\t\t\t\t+ \"TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM \"\n\t\t\t\t\t\t+ \"(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, \"\n\t\t\t\t\t\t+ \"EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID, ROW_NUMBER() \"\n\t\t\t\t\t\t+ \"OVER() as TMP_ROW_NUM FROM \"\n\t\t\t\t\t\t+ \"(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, \"\n\t\t\t\t\t\t+ \"EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM %PREFIX%EXECUTION ORDER BY START_TIME DESC, TASK_EXECUTION_ID DESC)) \"\n\t\t\t\t\t\t+ \"WHERE TMP_ROW_NUM >= 1 AND TMP_ROW_NUM < 11\" } });\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void testGeneratedQuery(String databaseProductName, String expectedQuery) throws Exception {\n\t\tString actualQuery = TestDBUtils.getPagingQueryProvider(databaseProductName).getPageQuery(this.pageable);\n\t\tassertThat(actualQuery)\n\t\t\t.as(String.format(\"the generated query for %s, was not the expected query\", databaseProductName))\n\t\t\t.isEqualTo(expectedQuery);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/H2PagingQueryProviderTests.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport org.h2.engine.Mode.ModeEnum;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.EnumSource;\n\nimport org.springframework.batch.infrastructure.item.database.Order;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.SimpleDriverDataSource;\nimport org.springframework.jdbc.support.JdbcTransactionManager;\nimport org.springframework.transaction.PlatformTransactionManager;\nimport org.springframework.transaction.support.TransactionTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Henning Pöttker\n * @author Mahmoud Ben Hassine\n */\nclass H2PagingQueryProviderTests {\n\n\t@ParameterizedTest\n\t@EnumSource(ModeEnum.class)\n\tvoid testH2PagingQueryProvider(ModeEnum mode) {\n\t\tString connectionUrl = String.format(\"jdbc:h2:mem:%s;MODE=%s\", UUID.randomUUID(), mode);\n\t\tDataSource dataSource = new SimpleDriverDataSource(new org.h2.Driver(), connectionUrl, \"sa\", \"\");\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\tPlatformTransactionManager transactionManager = new JdbcTransactionManager(dataSource);\n\t\tTransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);\n\n\t\ttransactionTemplate.executeWithoutResult(status -> {\n\t\t\tjdbcTemplate.execute(\"CREATE TABLE TEST_TABLE (ID BIGINT NOT NULL, STRING VARCHAR(10) NOT NULL)\");\n\t\t\tjdbcTemplate.execute(\"INSERT INTO TEST_TABLE (ID, STRING) VALUES (1, 'Spring')\");\n\t\t\tjdbcTemplate.execute(\"INSERT INTO TEST_TABLE (ID, STRING) VALUES (2, 'Cloud')\");\n\t\t\tjdbcTemplate.execute(\"INSERT INTO TEST_TABLE (ID, STRING) VALUES (3, 'Task')\");\n\n\t\t\tH2PagingQueryProvider queryProvider = new H2PagingQueryProvider();\n\t\t\tqueryProvider.setSelectClause(\"STRING\");\n\t\t\tqueryProvider.setFromClause(\"TEST_TABLE\");\n\t\t\tMap<String, Order> sortKeys = new HashMap<>();\n\t\t\tsortKeys.put(\"ID\", Order.ASCENDING);\n\t\t\tqueryProvider.setSortKeys(sortKeys);\n\n\t\t\tList<String> firstPage = jdbcTemplate.queryForList(queryProvider.getPageQuery(PageRequest.of(0, 2)),\n\t\t\t\t\tString.class);\n\t\t\tassertThat(firstPage).containsExactly(\"Spring\", \"Cloud\");\n\n\t\t\tList<String> secondPage = jdbcTemplate.queryForList(queryProvider.getPageQuery(PageRequest.of(1, 2)),\n\t\t\t\t\tString.class);\n\t\t\tassertThat(secondPage).containsExactly(\"Task\");\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/InvalidPagingQueryProviderTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.cloud.task.util.TestDBUtils;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * @author Glenn Renfro\n */\npublic class InvalidPagingQueryProviderTests {\n\n\t@Test\n\tpublic void testInvalidDatabase() throws Exception {\n\t\tPageable pageable = PageRequest.of(0, 10);\n\t\tassertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> {\n\t\t\tTestDBUtils.getPagingQueryProvider(\"Invalid\").getPageQuery(pageable);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/SqlPagingQueryProviderFactoryBeanTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport java.util.Map;\nimport java.util.TreeMap;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.infrastructure.item.database.Order;\nimport org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao;\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.cloud.task.util.TestDBUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n */\npublic class SqlPagingQueryProviderFactoryBeanTests {\n\n\tprivate SqlPagingQueryProviderFactoryBean factoryBean;\n\n\t@BeforeEach\n\tpublic void setup() throws Exception {\n\t\tthis.factoryBean = new SqlPagingQueryProviderFactoryBean();\n\t\tthis.factoryBean.setDataSource(TestDBUtils.getMockDataSource(\"MySQL\"));\n\t\tthis.factoryBean.setDatabaseType(\"Oracle\");\n\t\tthis.factoryBean.setSelectClause(JdbcTaskExecutionDao.SELECT_CLAUSE);\n\t\tthis.factoryBean.setFromClause(JdbcTaskExecutionDao.FROM_CLAUSE);\n\t\tMap<String, Order> orderMap = new TreeMap<>();\n\t\torderMap.put(\"START_TIME\", Order.DESCENDING);\n\t\torderMap.put(\"TASK_EXECUTION_ID\", Order.DESCENDING);\n\t\tthis.factoryBean.setSortKeys(orderMap);\n\n\t}\n\n\t@Test\n\tpublic void testDatabaseType() throws Exception {\n\t\tPagingQueryProvider pagingQueryProvider = this.factoryBean.getObject();\n\t\tassertThat(pagingQueryProvider).isInstanceOf(OraclePagingQueryProvider.class);\n\t}\n\n\t@Test\n\tpublic void testIsSingleton() {\n\t\tassertThat(this.factoryBean.isSingleton()).isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/WhereClausePagingQueryProviderTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.database.support;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.cloud.task.util.TestDBUtils;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n */\npublic class WhereClausePagingQueryProviderTests {\n\n\tprivate Pageable pageable = PageRequest.of(0, 10);\n\n\tpublic static Collection<Object[]> data() {\n\t\treturn Arrays.asList(new Object[][] { { \"Oracle\", \"SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, \"\n\t\t\t\t+ \"EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM \"\n\t\t\t\t+ \"(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, \"\n\t\t\t\t+ \"EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID, ROWNUM as \"\n\t\t\t\t+ \"TMP_ROW_NUM FROM (SELECT TASK_EXECUTION_ID, START_TIME, \"\n\t\t\t\t+ \"END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, \"\n\t\t\t\t+ \"LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM %PREFIX%EXECUTION \"\n\t\t\t\t+ \"WHERE TASK_EXECUTION_ID = '0000' ORDER BY START_TIME DESC, \"\n\t\t\t\t+ \"TASK_EXECUTION_ID DESC)) WHERE TMP_ROW_NUM >= 1 AND \" + \"TMP_ROW_NUM < 11\" },\n\t\t\t\t{ \"HSQL Database Engine\", \"SELECT LIMIT 0 10 TASK_EXECUTION_ID, \"\n\t\t\t\t\t\t+ \"START_TIME, END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, \"\n\t\t\t\t\t\t+ \"ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM %PREFIX%EXECUTION \"\n\t\t\t\t\t\t+ \"WHERE TASK_EXECUTION_ID = '0000' ORDER BY \" + \"START_TIME DESC, TASK_EXECUTION_ID DESC\" },\n\t\t\t\t{ \"PostgreSQL\", \"SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, \"\n\t\t\t\t\t\t+ \"TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID \"\n\t\t\t\t\t\t+ \"FROM %PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = '0000' \" + \"ORDER BY START_TIME DESC, \"\n\t\t\t\t\t\t+ \"TASK_EXECUTION_ID DESC LIMIT 10 OFFSET 0\" },\n\t\t\t\t{ \"MySQL\", \"SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, \"\n\t\t\t\t\t\t+ \"EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM \"\n\t\t\t\t\t\t+ \"%PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = '0000' \" + \"ORDER BY START_TIME DESC, \"\n\t\t\t\t\t\t+ \"TASK_EXECUTION_ID DESC LIMIT 0, 10\" },\n\t\t\t\t{ \"Microsoft SQL Server\", \"SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, \"\n\t\t\t\t\t\t+ \"TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM \"\n\t\t\t\t\t\t+ \"(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, \"\n\t\t\t\t\t\t+ \"EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID, ROW_NUMBER() \"\n\t\t\t\t\t\t+ \"OVER (ORDER BY START_TIME DESC, TASK_EXECUTION_ID DESC) AS \"\n\t\t\t\t\t\t+ \"TMP_ROW_NUM  FROM %PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = \"\n\t\t\t\t\t\t+ \"'0000') TASK_EXECUTION_PAGE  WHERE TMP_ROW_NUM >= 1 \"\n\t\t\t\t\t\t+ \"AND TMP_ROW_NUM < 11 ORDER BY START_TIME DESC, TASK_EXECUTION_ID DESC\" } });\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void testGeneratedQuery(String databaseProductName, String expectedQuery) throws Exception {\n\t\tPagingQueryProvider pagingQueryProvider = TestDBUtils.getPagingQueryProvider(databaseProductName,\n\t\t\t\t\"TASK_EXECUTION_ID = '0000'\");\n\t\tString actualQuery = pagingQueryProvider.getPageQuery(this.pageable);\n\t\tassertThat(actualQuery)\n\t\t\t.as(String.format(\"the generated query for %s, was not the expected query\", databaseProductName))\n\t\t\t.isEqualTo(expectedQuery);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/DatabaseTypeTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.cloud.task.util.TestDBUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.HSQL;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.MARIADB;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.MYSQL;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.ORACLE;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.POSTGRES;\nimport static org.springframework.cloud.task.repository.support.DatabaseType.fromProductName;\n\n/**\n * Tests that the correct database names are selected from datasource metadata.\n *\n * @author Lucas Ward\n * @author Will Schipp\n * @author Glenn Renfro\n *\n */\npublic class DatabaseTypeTests {\n\n\t@Test\n\tpublic void testFromProductName() {\n\t\tassertThat(fromProductName(\"HSQL Database Engine\")).isEqualTo(HSQL);\n\t\tassertThat(fromProductName(\"Oracle\")).isEqualTo(ORACLE);\n\t\tassertThat(fromProductName(\"PostgreSQL\")).isEqualTo(POSTGRES);\n\t\tassertThat(fromProductName(\"MySQL\")).isEqualTo(MYSQL);\n\t\tassertThat(fromProductName(\"MariaDB\")).isEqualTo(MARIADB);\n\t}\n\n\t@Test\n\tpublic void testInvalidProductName() {\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> fromProductName(\"bad product name\"));\n\t}\n\n\t@Test\n\tpublic void testFromMetaDataForHsql() throws Exception {\n\t\tDataSource ds = TestDBUtils.getMockDataSource(\"HSQL Database Engine\");\n\t\tassertThat(DatabaseType.fromMetaData(ds)).isEqualTo(HSQL);\n\t}\n\n\t@Test\n\tpublic void testFromMetaDataForOracle() throws Exception {\n\t\tDataSource ds = TestDBUtils.getMockDataSource(\"Oracle\");\n\t\tassertThat(DatabaseType.fromMetaData(ds)).isEqualTo(ORACLE);\n\t}\n\n\t@Test\n\tpublic void testFromMetaDataForPostgres() throws Exception {\n\t\tDataSource ds = TestDBUtils.getMockDataSource(\"PostgreSQL\");\n\t\tassertThat(DatabaseType.fromMetaData(ds)).isEqualTo(POSTGRES);\n\t}\n\n\t@Test\n\tpublic void testFromMetaDataForMySQL() throws Exception {\n\t\tDataSource ds = TestDBUtils.getMockDataSource(\"MySQL\");\n\t\tassertThat(DatabaseType.fromMetaData(ds)).isEqualTo(MYSQL);\n\t}\n\n\t@Test\n\tpublic void testFromMetaDataForMariaDB() throws Exception {\n\t\tDataSource ds = TestDBUtils.getMockDataSource(\"MariaDB\");\n\t\tassertThat(DatabaseType.fromMetaData(ds)).isEqualTo(MARIADB);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskExplorerTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.params.ParameterizedTest;\nimport org.junit.jupiter.params.provider.MethodSource;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.AutowireCapableBeanFactory;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.cloud.task.configuration.TestConfiguration;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.util.TestVerifierUtils;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n * @author Gunnar Hillert\n */\npublic class SimpleTaskExplorerTests {\n\n\tprivate final static String TASK_NAME = \"FOOBAR\";\n\n\tprivate final static String EXTERNAL_EXECUTION_ID = \"123ABC\";\n\n\tprivate AnnotationConfigApplicationContext context;\n\n\t@Autowired\n\tprivate TaskExplorer taskExplorer;\n\n\t@Autowired\n\tprivate TaskRepository taskRepository;\n\n\tpublic static Collection<Object> data() {\n\t\treturn Arrays.asList(new Object[] { DaoType.jdbc, DaoType.map });\n\t}\n\n\tpublic void testDefaultContext(DaoType testType) {\n\t\tif (testType == DaoType.jdbc) {\n\t\t\tinitializeJdbcExplorerTest();\n\t\t}\n\t\telse {\n\t\t\tinitializeMapExplorerTest();\n\t\t}\n\t}\n\n\t@AfterEach\n\tpublic void close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void getTaskExecution(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tMap<Long, TaskExecution> expectedResults = createSampleDataSet(5);\n\t\tfor (Long taskExecutionId : expectedResults.keySet()) {\n\t\t\tTaskExecution actualTaskExecution = this.taskExplorer.getTaskExecution(taskExecutionId);\n\t\t\tassertThat(actualTaskExecution)\n\t\t\t\t.as(String.format(\"expected a taskExecution but got null for test type %s\", testType))\n\t\t\t\t.isNotNull();\n\t\t\tTestVerifierUtils.verifyTaskExecution(expectedResults.get(taskExecutionId), actualTaskExecution);\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void taskExecutionNotFound(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tcreateSampleDataSet(5);\n\n\t\tTaskExecution actualTaskExecution = this.taskExplorer.getTaskExecution(-5);\n\t\tassertThat(actualTaskExecution).as(String.format(\"expected null for actualTaskExecution %s\", testType))\n\t\t\t.isNull();\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void getTaskCountByTaskName(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tMap<Long, TaskExecution> expectedResults = createSampleDataSet(5);\n\t\tfor (Map.Entry<Long, TaskExecution> entry : expectedResults.entrySet()) {\n\t\t\tString taskName = entry.getValue().getTaskName();\n\t\t\tassertThat(this.taskExplorer.getTaskExecutionCountByTaskName(taskName))\n\t\t\t\t.as(String.format(\"task count for task name did not match expected result for testType %s\", testType))\n\t\t\t\t.isEqualTo(1);\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void getTaskCount(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tcreateSampleDataSet(33);\n\t\tassertThat(this.taskExplorer.getTaskExecutionCount())\n\t\t\t.as(String.format(\"task count did not match expected result for test Type %s\", testType))\n\t\t\t.isEqualTo(33);\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void getRunningTaskCount(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tcreateSampleDataSet(33);\n\t\tassertThat(this.taskExplorer.getRunningTaskExecutionCount())\n\t\t\t.as(String.format(\"task count did not match expected result for test Type %s\", testType))\n\t\t\t.isEqualTo(33);\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void findRunningTasks(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tfinal int TEST_COUNT = 2;\n\t\tfinal int COMPLETE_COUNT = 5;\n\n\t\tMap<Long, TaskExecution> expectedResults = new HashMap<>();\n\t\t// Store completed task executions\n\t\tint i = 0;\n\t\tfor (; i < COMPLETE_COUNT; i++) {\n\t\t\tcreateAndSaveTaskExecution(i);\n\t\t}\n\n\t\tfor (; i < (COMPLETE_COUNT + TEST_COUNT); i++) {\n\t\t\tTaskExecution expectedTaskExecution = this.taskRepository.createTaskExecution(getSimpleTaskExecution());\n\t\t\texpectedResults.put(expectedTaskExecution.getExecutionId(), expectedTaskExecution);\n\t\t}\n\t\tPageable pageable = PageRequest.of(0, 10);\n\n\t\tPage<TaskExecution> actualResults = this.taskExplorer.findRunningTaskExecutions(TASK_NAME, pageable);\n\t\tassertThat(actualResults.getNumberOfElements())\n\t\t\t.as(String.format(\"Running task count for task name did not match expected result for testType %s\",\n\t\t\t\t\ttestType))\n\t\t\t.isEqualTo(TEST_COUNT);\n\n\t\tfor (TaskExecution result : actualResults) {\n\t\t\tassertThat(expectedResults.containsKey(result.getExecutionId()))\n\t\t\t\t.as(String.format(\"result returned from repo %s not expected for testType %s\", result.getExecutionId(),\n\t\t\t\t\t\ttestType))\n\t\t\t\t.isTrue();\n\t\t\tassertThat(result.getEndTime())\n\t\t\t\t.as(String.format(\"result had non null for endTime for the testType %s\", testType))\n\t\t\t\t.isNull();\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void findTasksByExternalExecutionId(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tMap<Long, TaskExecution> sampleDataSet = createSampleDataSet(33);\n\t\tsampleDataSet.values().forEach(taskExecution -> {\n\t\t\tPage<TaskExecution> taskExecutionsByExecutionId = this.taskExplorer\n\t\t\t\t.findTaskExecutionsByExecutionId(taskExecution.getExternalExecutionId(), PageRequest.of(0, 5));\n\t\t\tassertThat(taskExecutionsByExecutionId.getTotalElements()).isEqualTo(1);\n\t\t\tassertThat(this.taskExplorer\n\t\t\t\t.getTaskExecutionCountByExternalExecutionId(taskExecution.getExternalExecutionId())).isEqualTo(1);\n\t\t\tTaskExecution resultTaskExecution = taskExecutionsByExecutionId.getContent().get(0);\n\t\t\tassertThat(resultTaskExecution.getExecutionId()).isEqualTo(taskExecution.getExecutionId());\n\t\t});\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void findTasksByExternalExecutionIdMultipleEntry(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\n\t\ttestDefaultContext(testType);\n\t\tfinal int SAME_EXTERNAL_ID_COUNT = 2;\n\t\tfinal int UNIQUE_COUNT = 3;\n\n\t\tMap<Long, TaskExecution> expectedResults = new HashMap<>();\n\t\t// Store task executions each with a unique external execution id\n\t\tint i = 0;\n\t\tfor (; i < UNIQUE_COUNT; i++) {\n\t\t\tcreateAndSaveTaskExecution(i);\n\t\t}\n\t\t// Create task execution with same external execution id\n\t\tfor (; i < (UNIQUE_COUNT + SAME_EXTERNAL_ID_COUNT); i++) {\n\t\t\tTaskExecution expectedTaskExecution = this.taskRepository.createTaskExecution(getSimpleTaskExecution());\n\t\t\texpectedResults.put(expectedTaskExecution.getExecutionId(), expectedTaskExecution);\n\t\t}\n\t\tPageable pageable = PageRequest.of(0, 10);\n\t\tPage<TaskExecution> resultSet = this.taskExplorer.findTaskExecutionsByExecutionId(EXTERNAL_EXECUTION_ID,\n\t\t\t\tpageable);\n\t\tassertThat(resultSet.getTotalElements()).isEqualTo(SAME_EXTERNAL_ID_COUNT);\n\t\tList<TaskExecution> taskExecutions = resultSet.getContent();\n\t\ttaskExecutions.forEach(taskExecution -> {\n\t\t\tassertThat(expectedResults.keySet()).contains(taskExecution.getExecutionId());\n\t\t});\n\t\tassertThat(this.taskExplorer.getTaskExecutionCountByExternalExecutionId(EXTERNAL_EXECUTION_ID))\n\t\t\t.isEqualTo(SAME_EXTERNAL_ID_COUNT);\n\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void findTasksByName(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tfinal int TEST_COUNT = 5;\n\t\tfinal int COMPLETE_COUNT = 7;\n\n\t\tMap<Long, TaskExecution> expectedResults = new HashMap<>();\n\t\t// Store completed task executions\n\t\tfor (int i = 0; i < COMPLETE_COUNT; i++) {\n\t\t\tcreateAndSaveTaskExecution(i);\n\t\t}\n\n\t\tfor (int i = 0; i < TEST_COUNT; i++) {\n\t\t\tTaskExecution expectedTaskExecution = this.taskRepository.createTaskExecution(getSimpleTaskExecution());\n\t\t\texpectedResults.put(expectedTaskExecution.getExecutionId(), expectedTaskExecution);\n\t\t}\n\n\t\tPageable pageable = PageRequest.of(0, 10);\n\t\tPage<TaskExecution> resultSet = this.taskExplorer.findTaskExecutionsByName(TASK_NAME, pageable);\n\t\tassertThat(resultSet.getNumberOfElements())\n\t\t\t.as(String.format(\"Running task count for task name did not match expected result for testType %s\",\n\t\t\t\t\ttestType))\n\t\t\t.isEqualTo(TEST_COUNT);\n\n\t\tfor (TaskExecution result : resultSet) {\n\t\t\tassertThat(expectedResults.containsKey(result.getExecutionId()))\n\t\t\t\t.as(String.format(\"result returned from %s repo %s not expected\", testType, result.getExecutionId()))\n\t\t\t\t.isTrue();\n\t\t\tassertThat(result.getTaskName())\n\t\t\t\t.as(String.format(\"taskName for taskExecution is incorrect for testType %s\", testType))\n\t\t\t\t.isEqualTo(TASK_NAME);\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void getTaskNames(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tfinal int TEST_COUNT = 5;\n\t\tSet<String> expectedResults = new HashSet<>();\n\t\tfor (int i = 0; i < TEST_COUNT; i++) {\n\t\t\tTaskExecution expectedTaskExecution = createAndSaveTaskExecution(i);\n\t\t\texpectedResults.add(expectedTaskExecution.getTaskName());\n\t\t}\n\t\tList<String> actualTaskNames = this.taskExplorer.getTaskNames();\n\t\tfor (String taskName : actualTaskNames) {\n\t\t\tassertThat(expectedResults.contains(taskName))\n\t\t\t\t.as(String.format(\"taskName was not in expected results for testType %s\", testType))\n\t\t\t\t.isTrue();\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void findAllExecutionsOffBoundry(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tPageable pageable = PageRequest.of(0, 10);\n\t\tverifyPageResults(pageable, 103);\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void findAllExecutionsOffBoundryByOne(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tPageable pageable = PageRequest.of(0, 10);\n\t\tverifyPageResults(pageable, 101);\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void findAllExecutionsOnBoundry(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tPageable pageable = PageRequest.of(0, 10);\n\t\tverifyPageResults(pageable, 100);\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void findAllExecutionsNoResult(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tPageable pageable = PageRequest.of(0, 10);\n\t\tverifyPageResults(pageable, 0);\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void findTasksForInvalidJob(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tassertThat(this.taskExplorer.getTaskExecutionIdByJobExecutionId(55555L)).isNull();\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void findJobsExecutionIdsForInvalidTask(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tassertThat(this.taskExplorer.getJobExecutionIdsByTaskExecutionId(555555L).size()).isEqualTo(0);\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void getLatestTaskExecutionForTaskName(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tMap<Long, TaskExecution> expectedResults = createSampleDataSet(5);\n\t\tfor (Map.Entry<Long, TaskExecution> taskExecutionMapEntry : expectedResults.entrySet()) {\n\t\t\tTaskExecution latestTaskExecution = this.taskExplorer\n\t\t\t\t.getLatestTaskExecutionForTaskName(taskExecutionMapEntry.getValue().getTaskName());\n\t\t\tassertThat(latestTaskExecution)\n\t\t\t\t.as(String.format(\"expected a taskExecution but got null for test type %s\", testType))\n\t\t\t\t.isNotNull();\n\t\t\tTestVerifierUtils.verifyTaskExecution(expectedResults.get(latestTaskExecution.getExecutionId()),\n\t\t\t\t\tlatestTaskExecution);\n\t\t}\n\t}\n\n\t@ParameterizedTest\n\t@MethodSource(\"data\")\n\tpublic void getLatestTaskExecutionsByTaskNames(DaoType testType) {\n\t\ttestDefaultContext(testType);\n\t\tMap<Long, TaskExecution> expectedResults = createSampleDataSet(5);\n\n\t\tfinal List<String> taskNamesAsList = new ArrayList<>();\n\n\t\tfor (TaskExecution taskExecution : expectedResults.values()) {\n\t\t\ttaskNamesAsList.add(taskExecution.getTaskName());\n\t\t}\n\n\t\tfinal List<TaskExecution> latestTaskExecutions = this.taskExplorer\n\t\t\t.getLatestTaskExecutionsByTaskNames(taskNamesAsList.toArray(new String[taskNamesAsList.size()]));\n\n\t\tfor (TaskExecution latestTaskExecution : latestTaskExecutions) {\n\t\t\tassertThat(latestTaskExecution)\n\t\t\t\t.as(String.format(\"expected a taskExecution but got null for test type %s\", testType))\n\t\t\t\t.isNotNull();\n\t\t\tTestVerifierUtils.verifyTaskExecution(expectedResults.get(latestTaskExecution.getExecutionId()),\n\t\t\t\t\tlatestTaskExecution);\n\t\t}\n\t}\n\n\tprivate void verifyPageResults(Pageable pageable, int totalNumberOfExecs) {\n\t\tMap<Long, TaskExecution> expectedResults = createSampleDataSet(totalNumberOfExecs);\n\t\tList<Long> sortedExecIds = getSortedOfTaskExecIds(expectedResults);\n\t\tIterator<Long> expectedTaskExecutionIter = sortedExecIds.iterator();\n\t\t// Verify pageable totals\n\t\tPage<TaskExecution> taskPage = this.taskExplorer.findAll(pageable);\n\t\tint pagesExpected = (int) Math.ceil(totalNumberOfExecs / ((double) pageable.getPageSize()));\n\t\tassertThat(taskPage.getTotalPages()).as(\"actual page count return was not the expected total\")\n\t\t\t.isEqualTo(pagesExpected);\n\t\tassertThat(taskPage.getTotalElements()).as(\"actual element count was not the expected count\")\n\t\t\t.isEqualTo(totalNumberOfExecs);\n\n\t\t// Verify pagination\n\t\tPageable actualPageable = PageRequest.of(0, pageable.getPageSize());\n\t\tboolean hasMorePages = taskPage.hasContent();\n\t\tint pageNumber = 0;\n\t\tint elementCount = 0;\n\t\twhile (hasMorePages) {\n\t\t\ttaskPage = this.taskExplorer.findAll(actualPageable);\n\t\t\thasMorePages = taskPage.hasNext();\n\t\t\tList<TaskExecution> actualTaskExecutions = taskPage.getContent();\n\t\t\tint expectedPageSize = pageable.getPageSize();\n\t\t\tif (!hasMorePages && pageable.getPageSize() != actualTaskExecutions.size()) {\n\t\t\t\texpectedPageSize = totalNumberOfExecs % pageable.getPageSize();\n\t\t\t}\n\t\t\tassertThat(actualTaskExecutions.size())\n\t\t\t\t.as(String.format(\"Element count on page did not match on the %n page\", pageNumber))\n\t\t\t\t.isEqualTo(expectedPageSize);\n\t\t\tfor (TaskExecution actualExecution : actualTaskExecutions) {\n\t\t\t\tassertThat(actualExecution.getExecutionId())\n\t\t\t\t\t.as(String.format(\"Element on page %n did not match expected\", pageNumber))\n\t\t\t\t\t.isEqualTo((long) expectedTaskExecutionIter.next());\n\t\t\t\tTestVerifierUtils.verifyTaskExecution(expectedResults.get(actualExecution.getExecutionId()),\n\t\t\t\t\t\tactualExecution);\n\t\t\t\telementCount++;\n\t\t\t}\n\t\t\tactualPageable = taskPage.nextPageable();\n\t\t\tpageNumber++;\n\t\t}\n\t\t// Verify actual totals\n\t\tassertThat(pageNumber).as(\"Pages processed did not equal expected\").isEqualTo(pagesExpected);\n\t\tassertThat(elementCount).as(\"Elements processed did not equal expected,\").isEqualTo(totalNumberOfExecs);\n\t}\n\n\tprivate TaskExecution createAndSaveTaskExecution(int i) {\n\t\tTaskExecution taskExecution = TestVerifierUtils.createSampleTaskExecution(i);\n\t\ttaskExecution = this.taskRepository.createTaskExecution(taskExecution);\n\t\treturn taskExecution;\n\t}\n\n\tprivate void initializeJdbcExplorerTest() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.register(TestConfiguration.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.refresh();\n\n\t\tthis.context.getAutowireCapableBeanFactory()\n\t\t\t.autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);\n\t}\n\n\tprivate void initializeMapExplorerTest() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.register(TestConfiguration.class, PropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.refresh();\n\n\t\tthis.context.getAutowireCapableBeanFactory()\n\t\t\t.autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);\n\t}\n\n\tprivate Map<Long, TaskExecution> createSampleDataSet(int count) {\n\t\tMap<Long, TaskExecution> expectedResults = new HashMap<>();\n\t\tfor (int i = 0; i < count; i++) {\n\t\t\tTaskExecution expectedTaskExecution = createAndSaveTaskExecution(i);\n\t\t\texpectedResults.put(expectedTaskExecution.getExecutionId(), expectedTaskExecution);\n\t\t}\n\t\treturn expectedResults;\n\t}\n\n\tprivate List<Long> getSortedOfTaskExecIds(Map<Long, TaskExecution> taskExecutionMap) {\n\t\tList<Long> sortedExecIds = new ArrayList<>(taskExecutionMap.size());\n\t\tTreeSet<TaskExecution> sortedSet = getTreeSet();\n\t\tsortedSet.addAll(taskExecutionMap.values());\n\t\tIterator<TaskExecution> iterator = sortedSet.descendingIterator();\n\t\twhile (iterator.hasNext()) {\n\t\t\tsortedExecIds.add(iterator.next().getExecutionId());\n\t\t}\n\t\treturn sortedExecIds;\n\t}\n\n\tprivate TreeSet<TaskExecution> getTreeSet() {\n\t\treturn new TreeSet<>(new Comparator<TaskExecution>() {\n\t\t\t@Override\n\t\t\tpublic int compare(TaskExecution e1, TaskExecution e2) {\n\t\t\t\tint result = e1.getStartTime().compareTo(e2.getStartTime());\n\t\t\t\tif (result == 0) {\n\t\t\t\t\tresult = Long.valueOf(e1.getExecutionId()).compareTo(e2.getExecutionId());\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate TaskExecution getSimpleTaskExecution() {\n\t\tTaskExecution taskExecution = new TaskExecution();\n\t\ttaskExecution.setTaskName(TASK_NAME);\n\t\ttaskExecution.setStartTime(LocalDateTime.now());\n\t\ttaskExecution.setExternalExecutionId(EXTERNAL_EXECUTION_ID);\n\t\treturn taskExecution;\n\t}\n\n\tprivate enum DaoType {\n\n\t\tjdbc, map\n\n\t}\n\n\t@Configuration\n\tpublic static class DataSourceConfiguration {\n\n\t}\n\n\t@Configuration\n\tpublic static class EmptyConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskNameResolverTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.context.support.GenericApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Michael Minella\n */\npublic class SimpleTaskNameResolverTests {\n\n\t@Test\n\tpublic void testDefault() {\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\n\t\tSimpleTaskNameResolver taskNameResolver = new SimpleTaskNameResolver();\n\t\ttaskNameResolver.setApplicationContext(context);\n\n\t\tassertThat(taskNameResolver.getTaskName()\n\t\t\t.startsWith(\"org.springframework.context.support.GenericApplicationContext\")).isTrue();\n\t}\n\n\t@Test\n\tpublic void testWithProfile() {\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\tcontext.setId(\"foo:bar\");\n\n\t\tSimpleTaskNameResolver taskNameResolver = new SimpleTaskNameResolver();\n\t\ttaskNameResolver.setApplicationContext(context);\n\n\t\tassertThat(taskNameResolver.getTaskName().startsWith(\"foo_bar\")).isTrue();\n\t}\n\n\t@Test\n\tpublic void testApplicationName() {\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\tcontext.setId(\"foo\");\n\n\t\tSimpleTaskNameResolver taskNameResolver = new SimpleTaskNameResolver();\n\t\ttaskNameResolver.setApplicationContext(context);\n\n\t\tassertThat(taskNameResolver.getTaskName()).isEqualTo(\"foo\");\n\t}\n\n\t@Test\n\tpublic void testExternalConfig() {\n\t\tGenericApplicationContext context = new GenericApplicationContext();\n\t\tcontext.setId(\"foo\");\n\n\t\tSimpleTaskNameResolver taskNameResolver = new SimpleTaskNameResolver();\n\t\ttaskNameResolver.setApplicationContext(context);\n\n\t\ttaskNameResolver.setConfiguredName(\"bar\");\n\n\t\tassertThat(taskNameResolver.getTaskName()).isEqualTo(\"bar\");\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryJdbcTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport java.time.LocalDateTime;\nimport java.util.Collections;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.util.TaskExecutionCreator;\nimport org.springframework.cloud.task.util.TestDBUtils;\nimport org.springframework.cloud.task.util.TestVerifierUtils;\nimport org.springframework.test.annotation.DirtiesContext;\nimport org.springframework.test.context.ContextConfiguration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * Tests for the SimpleTaskRepository that uses JDBC as a datastore.\n *\n * @author Glenn Renfro.\n * @author Michael Minella\n * @author Ilayaperumal Gopinathan\n */\n@ExtendWith(SpringExtension.class)\n@ContextConfiguration(classes = { EmbeddedDataSourceConfiguration.class, SimpleTaskAutoConfiguration.class,\n\t\tPropertyPlaceholderAutoConfiguration.class })\n@DirtiesContext\npublic class SimpleTaskRepositoryJdbcTests {\n\n\t@Autowired\n\tprivate TaskRepository taskRepository;\n\n\t@Autowired\n\tprivate DataSource dataSource;\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testCreateEmptyExecution() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreEmptyTaskExecution(this.taskRepository);\n\t\tTaskExecution actualTaskExecution = TestDBUtils.getTaskExecutionFromDB(this.dataSource,\n\t\t\t\texpectedTaskExecution.getExecutionId());\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testCreateTaskExecutionNoParam() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\tTaskExecution actualTaskExecution = TestDBUtils.getTaskExecutionFromDB(this.dataSource,\n\t\t\t\texpectedTaskExecution.getExecutionId());\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testCreateTaskExecutionWithParam() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionWithParams(this.taskRepository);\n\t\tTaskExecution actualTaskExecution = TestDBUtils.getTaskExecutionFromDB(this.dataSource,\n\t\t\t\texpectedTaskExecution.getExecutionId());\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void startTaskExecutionWithParam() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreEmptyTaskExecution(this.taskRepository);\n\n\t\texpectedTaskExecution.setArguments(Collections.singletonList(\"foo=\" + UUID.randomUUID().toString()));\n\t\texpectedTaskExecution.setStartTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setTaskName(UUID.randomUUID().toString());\n\n\t\tTaskExecution actualTaskExecution = this.taskRepository.startTaskExecution(\n\t\t\t\texpectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void startTaskExecutionWithNoParam() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreEmptyTaskExecution(this.taskRepository);\n\n\t\texpectedTaskExecution.setStartTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setTaskName(UUID.randomUUID().toString());\n\n\t\tTaskExecution actualTaskExecution = this.taskRepository.startTaskExecution(\n\t\t\t\texpectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\t@Test\n\tpublic void testUpdateExternalExecutionId() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setExternalExecutionId(UUID.randomUUID().toString());\n\t\tthis.taskRepository.updateExternalExecutionId(expectedTaskExecution.getExecutionId(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tTestDBUtils.getTaskExecutionFromDB(this.dataSource, expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\tpublic void testUpdateNullExternalExecutionId() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setExternalExecutionId(null);\n\t\tthis.taskRepository.updateExternalExecutionId(expectedTaskExecution.getExecutionId(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tTestDBUtils.getTaskExecutionFromDB(this.dataSource, expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\tpublic void testInvalidExecutionIdForExternalExecutionIdUpdate() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setExternalExecutionId(null);\n\t\tassertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> {\n\t\t\tthis.taskRepository.updateExternalExecutionId(-1, expectedTaskExecution.getExternalExecutionId());\n\t\t});\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void startTaskExecutionWithParent() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreEmptyTaskExecution(this.taskRepository);\n\n\t\texpectedTaskExecution.setStartTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setTaskName(UUID.randomUUID().toString());\n\t\texpectedTaskExecution.setParentExecutionId(12345L);\n\n\t\tTaskExecution actualTaskExecution = this.taskRepository.startTaskExecution(\n\t\t\t\texpectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId(), expectedTaskExecution.getParentExecutionId());\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testCompleteTaskExecution() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setEndTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setExitCode(77);\n\t\texpectedTaskExecution.setExitMessage(UUID.randomUUID().toString());\n\n\t\tTaskExecution actualTaskExecution = TaskExecutionCreator.completeExecution(this.taskRepository,\n\t\t\t\texpectedTaskExecution);\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testCreateTaskExecutionNoParamMaxExitDefaultMessageSize() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setExitMessage(new String(new char[SimpleTaskRepository.MAX_EXIT_MESSAGE_SIZE + 1]));\n\t\texpectedTaskExecution.setEndTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setExitCode(0);\n\t\tTaskExecution actualTaskExecution = completeTaskExecution(expectedTaskExecution, this.taskRepository);\n\t\tassertThat(actualTaskExecution.getExitMessage().length()).isEqualTo(SimpleTaskRepository.MAX_EXIT_MESSAGE_SIZE);\n\t}\n\n\t@Test\n\tpublic void testCreateTaskExecutionNoParamMaxExitMessageSize() {\n\t\tSimpleTaskRepository simpleTaskRepository = new SimpleTaskRepository(\n\t\t\t\tnew TaskExecutionDaoFactoryBean(this.dataSource));\n\t\tsimpleTaskRepository.setMaxExitMessageSize(5);\n\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(simpleTaskRepository);\n\t\texpectedTaskExecution.setExitMessage(new String(new char[SimpleTaskRepository.MAX_EXIT_MESSAGE_SIZE + 1]));\n\t\texpectedTaskExecution.setEndTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setExitCode(0);\n\t\tTaskExecution actualTaskExecution = completeTaskExecution(expectedTaskExecution, simpleTaskRepository);\n\t\tassertThat(actualTaskExecution.getExitMessage().length()).isEqualTo(5);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testCreateTaskExecutionNoParamMaxErrorDefaultMessageSize() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setErrorMessage(new String(new char[SimpleTaskRepository.MAX_ERROR_MESSAGE_SIZE + 1]));\n\t\texpectedTaskExecution.setEndTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setExitCode(0);\n\t\tTaskExecution actualTaskExecution = completeTaskExecution(expectedTaskExecution, this.taskRepository);\n\t\tassertThat(actualTaskExecution.getErrorMessage().length())\n\t\t\t.isEqualTo(SimpleTaskRepository.MAX_ERROR_MESSAGE_SIZE);\n\t}\n\n\t@Test\n\tpublic void testCreateTaskExecutionNoParamMaxErrorMessageSize() {\n\t\tSimpleTaskRepository simpleTaskRepository = new SimpleTaskRepository(\n\t\t\t\tnew TaskExecutionDaoFactoryBean(this.dataSource));\n\t\tsimpleTaskRepository.setMaxErrorMessageSize(5);\n\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(simpleTaskRepository);\n\t\texpectedTaskExecution.setErrorMessage(new String(new char[SimpleTaskRepository.MAX_ERROR_MESSAGE_SIZE + 1]));\n\t\texpectedTaskExecution.setEndTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setExitCode(0);\n\t\tTaskExecution actualTaskExecution = completeTaskExecution(expectedTaskExecution, simpleTaskRepository);\n\t\tassertThat(actualTaskExecution.getErrorMessage().length()).isEqualTo(5);\n\t}\n\n\t@Test\n\tpublic void testMaxTaskNameSizeForConstructor() {\n\t\tfinal int MAX_EXIT_MESSAGE_SIZE = 10;\n\t\tfinal int MAX_ERROR_MESSAGE_SIZE = 20;\n\t\tfinal int MAX_TASK_NAME_SIZE = 30;\n\t\tSimpleTaskRepository simpleTaskRepository = new SimpleTaskRepository(\n\t\t\t\tnew TaskExecutionDaoFactoryBean(this.dataSource), MAX_EXIT_MESSAGE_SIZE, MAX_TASK_NAME_SIZE,\n\t\t\t\tMAX_ERROR_MESSAGE_SIZE);\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.createSampleTaskExecutionNoArg();\n\t\texpectedTaskExecution.setTaskName(new String(new char[MAX_TASK_NAME_SIZE + 1]));\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tsimpleTaskRepository.createTaskExecution(expectedTaskExecution);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testDefaultMaxTaskNameSizeForConstructor() {\n\t\tSimpleTaskRepository simpleTaskRepository = new SimpleTaskRepository(\n\t\t\t\tnew TaskExecutionDaoFactoryBean(this.dataSource), null, null, null);\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.createSampleTaskExecutionNoArg();\n\t\texpectedTaskExecution.setTaskName(new String(new char[SimpleTaskRepository.MAX_TASK_NAME_SIZE + 1]));\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tsimpleTaskRepository.createTaskExecution(expectedTaskExecution);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testMaxSizeConstructor() {\n\t\tfinal int MAX_EXIT_MESSAGE_SIZE = 10;\n\t\tfinal int MAX_ERROR_MESSAGE_SIZE = 20;\n\t\tSimpleTaskRepository simpleTaskRepository = new SimpleTaskRepository(\n\t\t\t\tnew TaskExecutionDaoFactoryBean(this.dataSource), MAX_EXIT_MESSAGE_SIZE, null, MAX_ERROR_MESSAGE_SIZE);\n\t\tverifyTaskRepositoryConstructor(MAX_EXIT_MESSAGE_SIZE, MAX_ERROR_MESSAGE_SIZE, simpleTaskRepository);\n\t}\n\n\t@Test\n\tpublic void testDefaultConstructor() {\n\t\tSimpleTaskRepository simpleTaskRepository = new SimpleTaskRepository(\n\t\t\t\tnew TaskExecutionDaoFactoryBean(this.dataSource), null, null, null);\n\t\tverifyTaskRepositoryConstructor(SimpleTaskRepository.MAX_EXIT_MESSAGE_SIZE,\n\t\t\t\tSimpleTaskRepository.MAX_ERROR_MESSAGE_SIZE, simpleTaskRepository);\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testCreateTaskExecutionNoParamMaxTaskName() {\n\t\tTaskExecution taskExecution = new TaskExecution();\n\t\ttaskExecution.setTaskName(new String(new char[SimpleTaskRepository.MAX_TASK_NAME_SIZE + 1]));\n\t\ttaskExecution.setStartTime(LocalDateTime.now());\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tthis.taskRepository.createTaskExecution(taskExecution);\n\t\t});\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testCreateTaskExecutionNegativeException() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setEndTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setExitCode(-1);\n\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tTaskExecution actualTaskExecution = TaskExecutionCreator.completeExecution(this.taskRepository,\n\t\t\t\t\texpectedTaskExecution);\n\t\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t\t});\n\t}\n\n\t@Test\n\t@DirtiesContext\n\tpublic void testCreateTaskExecutionNullEndTime() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setExitCode(-1);\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tTaskExecutionCreator.completeExecution(this.taskRepository, expectedTaskExecution);\n\t\t});\n\t}\n\n\tprivate TaskExecution completeTaskExecution(TaskExecution expectedTaskExecution, TaskRepository taskRepository) {\n\t\treturn taskRepository.completeTaskExecution(expectedTaskExecution.getExecutionId(),\n\t\t\t\texpectedTaskExecution.getExitCode(), LocalDateTime.now(), expectedTaskExecution.getExitMessage(),\n\t\t\t\texpectedTaskExecution.getErrorMessage());\n\t}\n\n\tprivate void verifyTaskRepositoryConstructor(Integer maxExitMessage, Integer maxErrorMessage,\n\t\t\tTaskRepository taskRepository) {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator.createAndStoreTaskExecutionNoParams(taskRepository);\n\t\texpectedTaskExecution.setErrorMessage(new String(new char[maxErrorMessage + 1]));\n\t\texpectedTaskExecution.setExitMessage(new String(new char[maxExitMessage + 1]));\n\t\texpectedTaskExecution.setEndTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setExitCode(0);\n\n\t\tTaskExecution actualTaskExecution = completeTaskExecution(expectedTaskExecution, taskRepository);\n\t\tassertThat(actualTaskExecution.getErrorMessage().length()).isEqualTo(maxErrorMessage.intValue());\n\t\tassertThat(actualTaskExecution.getExitMessage().length()).isEqualTo(maxExitMessage.intValue());\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryMapTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport java.time.LocalDateTime;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;\nimport org.springframework.cloud.task.util.TaskExecutionCreator;\nimport org.springframework.cloud.task.util.TestVerifierUtils;\n\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.springframework.test.util.AssertionErrors.assertTrue;\n\n/**\n * Tests for the SimpleTaskRepository that uses Map as a datastore.\n *\n * @author Glenn Renfro\n * @author Ilayaperumal Gopinathan\n */\npublic class SimpleTaskRepositoryMapTests {\n\n\tprivate TaskRepository taskRepository;\n\n\t@BeforeEach\n\tpublic void setUp() {\n\t\tthis.taskRepository = new SimpleTaskRepository(new TaskExecutionDaoFactoryBean());\n\t}\n\n\t@Test\n\tpublic void testCreateEmptyExecution() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreEmptyTaskExecution(this.taskRepository);\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tgetSingleTaskExecutionFromMapRepository(expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\tpublic void testCreateTaskExecutionNoParam() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tgetSingleTaskExecutionFromMapRepository(expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\tpublic void testUpdateExternalExecutionId() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setExternalExecutionId(UUID.randomUUID().toString());\n\t\tthis.taskRepository.updateExternalExecutionId(expectedTaskExecution.getExecutionId(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tgetSingleTaskExecutionFromMapRepository(expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\tpublic void testUpdateNullExternalExecutionId() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setExternalExecutionId(null);\n\t\tthis.taskRepository.updateExternalExecutionId(expectedTaskExecution.getExecutionId(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tgetSingleTaskExecutionFromMapRepository(expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\tpublic void testInvalidExecutionIdForExternalExecutionIdUpdate() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setExternalExecutionId(null);\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tthis.taskRepository.updateExternalExecutionId(-1, expectedTaskExecution.getExternalExecutionId());\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testCreateTaskExecutionWithParam() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionWithParams(this.taskRepository);\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution,\n\t\t\t\tgetSingleTaskExecutionFromMapRepository(expectedTaskExecution.getExecutionId()));\n\t}\n\n\t@Test\n\tpublic void startTaskExecutionWithParam() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreEmptyTaskExecution(this.taskRepository);\n\n\t\texpectedTaskExecution.setArguments(Collections.singletonList(\"foo=\" + UUID.randomUUID().toString()));\n\t\texpectedTaskExecution.setStartTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setTaskName(UUID.randomUUID().toString());\n\n\t\tTaskExecution actualTaskExecution = this.taskRepository.startTaskExecution(\n\t\t\t\texpectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId(), expectedTaskExecution.getParentExecutionId());\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\t@Test\n\tpublic void startTaskExecutionWithNoParam() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreEmptyTaskExecution(this.taskRepository);\n\n\t\texpectedTaskExecution.setStartTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setTaskName(UUID.randomUUID().toString());\n\n\t\tTaskExecution actualTaskExecution = this.taskRepository.startTaskExecution(\n\t\t\t\texpectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\t@Test\n\tpublic void startTaskExecutionWithParent() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreEmptyTaskExecution(this.taskRepository);\n\n\t\texpectedTaskExecution.setStartTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setTaskName(UUID.randomUUID().toString());\n\t\texpectedTaskExecution.setParentExecutionId(12345L);\n\n\t\tTaskExecution actualTaskExecution = this.taskRepository.startTaskExecution(\n\t\t\t\texpectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(),\n\t\t\t\texpectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(),\n\t\t\t\texpectedTaskExecution.getExternalExecutionId());\n\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\t@Test\n\tpublic void testCompleteTaskExecution() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setEndTime(LocalDateTime.now());\n\t\texpectedTaskExecution.setExitCode(0);\n\t\tTaskExecution actualTaskExecution = TaskExecutionCreator.completeExecution(this.taskRepository,\n\t\t\t\texpectedTaskExecution);\n\t\tTestVerifierUtils.verifyTaskExecution(expectedTaskExecution, actualTaskExecution);\n\t}\n\n\tprivate TaskExecution getSingleTaskExecutionFromMapRepository(long taskExecutionId) {\n\t\tMap<Long, TaskExecution> taskMap = ((MapTaskExecutionDao) ((SimpleTaskRepository) this.taskRepository)\n\t\t\t.getTaskExecutionDao()).getTaskExecutions();\n\t\tassertTrue(\"taskExecutionId must be in MapTaskExecutionRepository\", taskMap.containsKey(taskExecutionId));\n\t\treturn taskMap.get(taskExecutionId);\n\t}\n\n\t@Test\n\tpublic void testCreateTaskExecutionNullEndTime() {\n\t\tTaskExecution expectedTaskExecution = TaskExecutionCreator\n\t\t\t.createAndStoreTaskExecutionNoParams(this.taskRepository);\n\t\texpectedTaskExecution.setExitCode(-1);\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tTaskExecutionCreator.completeExecution(this.taskRepository, expectedTaskExecution);\n\t\t});\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskDatabaseInitializerTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.beans.factory.BeanCreationException;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.jdbc.autoconfigure.EmbeddedDataSourceConfiguration;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.configuration.TestConfiguration;\nimport org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.core.JdbcTemplate;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\nimport static org.mockito.Mockito.mock;\n\n/**\n * Verifies that task initialization occurs properly.\n *\n * @author Glenn Renfro\n */\npublic class TaskDatabaseInitializerTests {\n\n\tprivate AnnotationConfigApplicationContext context;\n\n\t@AfterEach\n\tpublic void close() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testDefaultContext() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.register(TestConfiguration.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(new JdbcTemplate(this.context.getBean(DataSource.class)).queryForList(\"select * from TASK_EXECUTION\")\n\t\t\t.size()).isEqualTo(0);\n\t}\n\n\t@Test\n\tpublic void testNoDatabase() {\n\t\tthis.context = new AnnotationConfigApplicationContext(EmptyConfiguration.class);\n\t\tSimpleTaskRepository repository = new SimpleTaskRepository(new TaskExecutionDaoFactoryBean());\n\t\tassertThat(repository.getTaskExecutionDao()).isInstanceOf(MapTaskExecutionDao.class);\n\t\tMapTaskExecutionDao dao = (MapTaskExecutionDao) repository.getTaskExecutionDao();\n\t\tassertThat(dao.getTaskExecutions().size()).isEqualTo(0);\n\t}\n\n\t@Test\n\tpublic void testNoTaskConfiguration() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.register(EmptyConfiguration.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class);\n\t\tthis.context.refresh();\n\t\tassertThat(this.context.getBeanNamesForType(SimpleTaskRepository.class).length).isEqualTo(0);\n\t}\n\n\t@Test\n\tpublic void testMultipleDataSourcesContext() {\n\t\tthis.context = new AnnotationConfigApplicationContext();\n\t\tthis.context.register(SimpleTaskAutoConfiguration.class, EmbeddedDataSourceConfiguration.class,\n\t\t\t\tPropertyPlaceholderAutoConfiguration.class);\n\t\tDataSource dataSource = mock(DataSource.class);\n\t\tthis.context.getBeanFactory().registerSingleton(\"mockDataSource\", dataSource);\n\t\tassertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> {\n\t\t\tthis.context.refresh();\n\t\t});\n\t}\n\n\t@Configuration\n\tpublic static class EmptyConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskExecutionDaoFactoryBeanTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.repository.support;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao;\nimport org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;\nimport org.springframework.cloud.task.repository.dao.TaskExecutionDao;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.test.util.ReflectionTestUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * @author Michael Minella\n */\npublic class TaskExecutionDaoFactoryBeanTests {\n\n\tprivate ConfigurableApplicationContext context;\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.context != null) {\n\t\t\tthis.context.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testGetObjectType() {\n\t\tassertThat(TaskExecutionDao.class).isEqualTo(new TaskExecutionDaoFactoryBean().getObjectType());\n\t}\n\n\t@Test\n\tpublic void testIsSingleton() {\n\t\tassertThat(new TaskExecutionDaoFactoryBean().isSingleton()).isTrue();\n\t}\n\n\t@Test\n\tpublic void testConstructorValidation() {\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tnew TaskExecutionDaoFactoryBean(null);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testMapTaskExecutionDaoWithoutAppContext() throws Exception {\n\t\tTaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean();\n\t\tTaskExecutionDao taskExecutionDao = factoryBean.getObject();\n\n\t\tassertThat(taskExecutionDao instanceof MapTaskExecutionDao).isTrue();\n\n\t\tTaskExecutionDao taskExecutionDao2 = factoryBean.getObject();\n\n\t\tassertThat(taskExecutionDao == taskExecutionDao2).isTrue();\n\t}\n\n\t@Test\n\tpublic void testDefaultDataSourceConfiguration() throws Exception {\n\t\tthis.context = new AnnotationConfigApplicationContext(DefaultDataSourceConfiguration.class);\n\n\t\tDataSource dataSource = this.context.getBean(DataSource.class);\n\n\t\tTaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(dataSource);\n\t\tTaskExecutionDao taskExecutionDao = factoryBean.getObject();\n\n\t\tassertThat(taskExecutionDao instanceof JdbcTaskExecutionDao).isTrue();\n\n\t\tTaskExecutionDao taskExecutionDao2 = factoryBean.getObject();\n\n\t\tassertThat(taskExecutionDao == taskExecutionDao2).isTrue();\n\t}\n\n\t@Test\n\tpublic void testSettingTablePrefix() throws Exception {\n\t\tthis.context = new AnnotationConfigApplicationContext(DefaultDataSourceConfiguration.class);\n\n\t\tDataSource dataSource = this.context.getBean(DataSource.class);\n\n\t\tTaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(dataSource, \"foo_\");\n\t\tTaskExecutionDao taskExecutionDao = factoryBean.getObject();\n\n\t\tassertThat(ReflectionTestUtils.getField(taskExecutionDao, \"tablePrefix\")).isEqualTo(\"foo_\");\n\t}\n\n\t@Configuration\n\tpublic static class DefaultDataSourceConfiguration {\n\n\t\t@Bean\n\t\tpublic DataSource dataSource() {\n\t\t\tEmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2);\n\t\t\treturn builder.build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TaskExecutionCreator.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.util;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskRepository;\n\n/**\n * Offers ability to create TaskExecutions for the test suite.\n *\n * @author Glenn Renfro\n */\npublic final class TaskExecutionCreator {\n\n\tprivate TaskExecutionCreator() {\n\t}\n\n\t/**\n\t * Creates a sample TaskExecution and stores it in the taskRepository.\n\t * @param taskRepository the taskRepository where the taskExecution should be stored.\n\t * @return the taskExecution created.\n\t */\n\tpublic static TaskExecution createAndStoreEmptyTaskExecution(TaskRepository taskRepository) {\n\t\treturn taskRepository.createTaskExecution();\n\t}\n\n\t/**\n\t * Creates a sample TaskExecution and stores it in the taskRepository.\n\t * @param taskRepository the taskRepository where the taskExecution should be stored.\n\t * @return the taskExecution created.\n\t */\n\tpublic static TaskExecution createAndStoreTaskExecutionNoParams(TaskRepository taskRepository) {\n\t\tTaskExecution expectedTaskExecution = taskRepository.createTaskExecution();\n\t\treturn expectedTaskExecution;\n\t}\n\n\t/**\n\t * Creates a sample TaskExecution and stores it in the taskRepository with params.\n\t * @param taskRepository the taskRepository where the taskExecution should be stored.\n\t * @return the taskExecution created.\n\t */\n\tpublic static TaskExecution createAndStoreTaskExecutionWithParams(TaskRepository taskRepository) {\n\t\tTaskExecution expectedTaskExecution = TestVerifierUtils.createSampleTaskExecutionNoArg();\n\t\tList<String> params = new ArrayList<>();\n\t\tparams.add(UUID.randomUUID().toString());\n\t\tparams.add(UUID.randomUUID().toString());\n\t\texpectedTaskExecution.setArguments(params);\n\t\texpectedTaskExecution = taskRepository.createTaskExecution(expectedTaskExecution);\n\t\treturn expectedTaskExecution;\n\t}\n\n\t/**\n\t * Updates a sample TaskExecution in the taskRepository.\n\t * @param taskRepository the taskRepository where the taskExecution should be updated.\n\t * @param expectedTaskExecution the expected task execution.\n\t * @return the taskExecution created.\n\t */\n\tpublic static TaskExecution completeExecution(TaskRepository taskRepository, TaskExecution expectedTaskExecution) {\n\t\treturn taskRepository.completeTaskExecution(expectedTaskExecution.getExecutionId(),\n\t\t\t\texpectedTaskExecution.getExitCode(), expectedTaskExecution.getEndTime(),\n\t\t\t\texpectedTaskExecution.getExitMessage(), expectedTaskExecution.getErrorMessage());\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDBUtils.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.util;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.batch.infrastructure.item.database.Order;\nimport org.springframework.batch.infrastructure.item.database.support.DataFieldMaxValueIncrementerFactory;\nimport org.springframework.batch.infrastructure.item.database.support.DefaultDataFieldMaxValueIncrementerFactory;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao;\nimport org.springframework.cloud.task.repository.database.PagingQueryProvider;\nimport org.springframework.cloud.task.repository.database.support.SqlPagingQueryProviderFactoryBean;\nimport org.springframework.cloud.task.repository.support.DatabaseType;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.RowMapper;\nimport org.springframework.jdbc.support.MetaDataAccessException;\nimport org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;\nimport org.springframework.util.StringUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\n/**\n * Provides a suite of tools that allow tests the ability to retrieve results from a\n * relational database.\n *\n * @author Glenn Renfro\n * @author Ilayaperumal Gopinathan\n */\npublic final class TestDBUtils {\n\n\tprivate TestDBUtils() {\n\t}\n\n\t/**\n\t * Retrieves the TaskExecution from the datasource.\n\t * @param dataSource The datasource from which to retrieve the taskExecution.\n\t * @param taskExecutionId The id of the task to search.\n\t * @return taskExecution retrieved from the database.\n\t */\n\tpublic static TaskExecution getTaskExecutionFromDB(DataSource dataSource, long taskExecutionId) {\n\t\tString sql = \"SELECT * FROM TASK_EXECUTION WHERE \" + \"TASK_EXECUTION_ID = '\" + taskExecutionId + \"'\";\n\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\tList<TaskExecution> rows = jdbcTemplate.query(sql, new RowMapper<TaskExecution>() {\n\t\t\t@Override\n\t\t\tpublic TaskExecution mapRow(ResultSet rs, int rownumber) throws SQLException {\n\t\t\t\tTaskExecution taskExecution = new TaskExecution(rs.getLong(\"TASK_EXECUTION_ID\"),\n\t\t\t\t\t\tStringUtils.hasText(rs.getString(\"EXIT_CODE\")) ? Integer.valueOf(rs.getString(\"EXIT_CODE\"))\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\trs.getString(\"TASK_NAME\"), rs.getObject(\"START_TIME\", LocalDateTime.class),\n\t\t\t\t\t\trs.getObject(\"END_TIME\", LocalDateTime.class), rs.getString(\"EXIT_MESSAGE\"), new ArrayList<>(0),\n\t\t\t\t\t\trs.getString(\"ERROR_MESSAGE\"), rs.getString(\"EXTERNAL_EXECUTION_ID\"));\n\t\t\t\treturn taskExecution;\n\t\t\t}\n\t\t});\n\t\tassertThat(rows.size()).as(\"only one row should be returned\").isEqualTo(1);\n\t\tTaskExecution taskExecution = rows.get(0);\n\n\t\tpopulateParamsToDB(dataSource, taskExecution);\n\t\treturn taskExecution;\n\t}\n\n\t/**\n\t * Create a pagingQueryProvider specific database type with a findAll.\n\t * @param databaseProductName of the database.\n\t * @return a {@link PagingQueryProvider} that will return all the requested\n\t * information.\n\t * @throws Exception exception thrown if error occurs creating\n\t * {@link PagingQueryProvider}.\n\t */\n\tpublic static PagingQueryProvider getPagingQueryProvider(String databaseProductName) throws Exception {\n\t\treturn getPagingQueryProvider(databaseProductName, null);\n\t}\n\n\t/**\n\t * Create a pagingQueryProvider specific database type with a query containing a where\n\t * clause.\n\t * @param databaseProductName of the database.\n\t * @param whereClause to be applied to the query.\n\t * @return a PagingQueryProvider that will return the requested information.\n\t * @throws Exception exception thrown if error occurs creating\n\t * {@link PagingQueryProvider}.\n\t */\n\tpublic static PagingQueryProvider getPagingQueryProvider(String databaseProductName, String whereClause)\n\t\t\tthrows Exception {\n\t\tDataSource dataSource = getMockDataSource(databaseProductName);\n\t\tMap<String, Order> orderMap = new TreeMap<>();\n\t\torderMap.put(\"START_TIME\", Order.DESCENDING);\n\t\torderMap.put(\"TASK_EXECUTION_ID\", Order.DESCENDING);\n\t\tSqlPagingQueryProviderFactoryBean factoryBean = new SqlPagingQueryProviderFactoryBean();\n\t\tfactoryBean.setSelectClause(JdbcTaskExecutionDao.SELECT_CLAUSE);\n\t\tfactoryBean.setFromClause(JdbcTaskExecutionDao.FROM_CLAUSE);\n\t\tif (whereClause != null) {\n\t\t\tfactoryBean.setWhereClause(whereClause);\n\t\t}\n\t\tfactoryBean.setSortKeys(orderMap);\n\t\tfactoryBean.setDataSource(dataSource);\n\t\tPagingQueryProvider pagingQueryProvider = null;\n\t\ttry {\n\t\t\tpagingQueryProvider = factoryBean.getObject();\n\t\t\tpagingQueryProvider.init(dataSource);\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tthrow new IllegalStateException(e);\n\t\t}\n\t\treturn pagingQueryProvider;\n\t}\n\n\t/**\n\t * Creates a mock DataSource for use in testing.\n\t * @param databaseProductName the name of the database type to mock.\n\t * @return a mock DataSource.\n\t * @throws Exception exception thrown if error occurs creating mock\n\t * {@link DataSource}.\n\t */\n\tpublic static DataSource getMockDataSource(String databaseProductName) throws Exception {\n\t\tDatabaseMetaData dmd = mock(DatabaseMetaData.class);\n\t\tDataSource ds = mock(DataSource.class);\n\t\tConnection con = mock(Connection.class);\n\t\twhen(ds.getConnection()).thenReturn(con);\n\t\twhen(con.getMetaData()).thenReturn(dmd);\n\t\twhen(dmd.getDatabaseProductName()).thenReturn(databaseProductName);\n\t\treturn ds;\n\t}\n\n\t/**\n\t * Creates a incrementer for the DataSource.\n\t * @param dataSource the datasource that the incrementer will use to record current\n\t * id.\n\t * @return a DataFieldMaxValueIncrementer object.\n\t */\n\tpublic static DataFieldMaxValueIncrementer getIncrementer(DataSource dataSource) {\n\t\tDataFieldMaxValueIncrementerFactory incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(\n\t\t\t\tdataSource);\n\t\tString databaseType = null;\n\t\ttry {\n\t\t\tdatabaseType = DatabaseType.fromMetaData(dataSource).name();\n\t\t}\n\t\tcatch (MetaDataAccessException e) {\n\t\t\tthrow new IllegalStateException(e);\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\tthrow new IllegalStateException(\"Unable to detect database type\", ex);\n\t\t}\n\t\treturn incrementerFactory.getIncrementer(databaseType, \"TASK_SEQ\");\n\t}\n\n\tprivate static void populateParamsToDB(DataSource dataSource, TaskExecution taskExecution) {\n\t\tString sql = \"SELECT * FROM TASK_EXECUTION_PARAMS WHERE TASK_EXECUTION_ID = '\" + taskExecution.getExecutionId()\n\t\t\t\t+ \"'\";\n\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\tList<Map<String, Object>> rows = jdbcTemplate.queryForList(sql);\n\t\tList<String> arguments = new ArrayList<>();\n\t\tfor (Map row : rows) {\n\t\t\targuments.add((String) row.get(\"TASK_PARAM\"));\n\t\t}\n\t\ttaskExecution.setArguments(arguments);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.util;\n\nimport javax.sql.DataSource;\n\nimport io.micrometer.observation.ObservationRegistry;\n\nimport org.springframework.beans.factory.InitializingBean;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.cloud.task.configuration.TaskObservationCloudKeyValues;\nimport org.springframework.cloud.task.configuration.TaskProperties;\nimport org.springframework.cloud.task.listener.TaskLifecycleListener;\nimport org.springframework.cloud.task.listener.TaskListenerExecutorObjectFactory;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.TaskNameResolver;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.repository.support.SimpleTaskExplorer;\nimport org.springframework.cloud.task.repository.support.SimpleTaskNameResolver;\nimport org.springframework.cloud.task.repository.support.SimpleTaskRepository;\nimport org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Initializes the beans needed to test default task behavior.\n *\n * @author Glenn Renfro\n * @author Michael Minella\n */\n@Configuration\n@EnableConfigurationProperties(TaskProperties.class)\npublic class TestDefaultConfiguration implements InitializingBean {\n\n\t@Autowired\n\tTaskProperties taskProperties;\n\n\tprivate TaskExecutionDaoFactoryBean factoryBean;\n\n\t@Autowired(required = false)\n\tprivate ApplicationArguments applicationArguments;\n\n\t@Autowired\n\tprivate ConfigurableApplicationContext context;\n\n\tpublic TestDefaultConfiguration() {\n\t}\n\n\t@Bean\n\tpublic TaskRepository taskRepository() {\n\t\treturn new SimpleTaskRepository(this.factoryBean);\n\t}\n\n\t@Bean\n\tpublic TaskExplorer taskExplorer() {\n\t\treturn new SimpleTaskExplorer(this.factoryBean);\n\t}\n\n\t@Bean\n\tpublic TaskNameResolver taskNameResolver() {\n\t\treturn new SimpleTaskNameResolver();\n\t}\n\n\t@Bean\n\tpublic TaskListenerExecutorObjectFactory taskListenerExecutorObjectProvider(\n\t\t\tConfigurableApplicationContext context) {\n\t\treturn new TaskListenerExecutorObjectFactory(context);\n\t}\n\n\t@Bean\n\tpublic TaskLifecycleListener taskHandler(TaskExplorer taskExplorer,\n\t\t\t@Autowired(required = false) io.micrometer.core.instrument.MeterRegistry meterRegistry,\n\t\t\t@Autowired(required = false) ObservationRegistry observationRegistry) {\n\n\t\treturn new TaskLifecycleListener(taskRepository(), taskNameResolver(), this.applicationArguments, taskExplorer,\n\t\t\t\tthis.taskProperties, taskListenerExecutorObjectProvider(this.context), observationRegistry,\n\t\t\t\tnew TaskObservationCloudKeyValues());\n\t}\n\n\t@Override\n\tpublic void afterPropertiesSet() throws Exception {\n\t\tif (this.context.getBeanNamesForType(DataSource.class).length == 1) {\n\t\t\tDataSource dataSource = this.context.getBean(DataSource.class);\n\t\t\tthis.factoryBean = new TaskExecutionDaoFactoryBean(dataSource);\n\t\t}\n\t\telse {\n\t\t\tthis.factoryBean = new TaskExecutionDaoFactoryBean();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestListener.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.util;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\n\n/**\n * Provides the basic infrastructure for evaluating if task listener performed properly.\n *\n * @author Glenn Renfro\n */\npublic abstract class TestListener {\n\n\t/**\n\t * Default end message to use for the start message.\n\t */\n\tpublic static final String START_MESSAGE = \"FOO\";\n\n\t/**\n\t * Default end message to use for the error message.\n\t */\n\tpublic static final String ERROR_MESSAGE = \"BAR\";\n\n\t/**\n\t * Default end message to use for the end message.\n\t */\n\tpublic static final String END_MESSAGE = \"BAZ\";\n\n\tprotected boolean isTaskStartup;\n\n\tprotected boolean isTaskEnd;\n\n\tprotected boolean isTaskFailed;\n\n\tprotected TaskExecution taskExecution;\n\n\tprotected Throwable throwable;\n\n\t/**\n\t * Indicates if the task listener was called during task create step.\n\t * @return true if task listener was called during task creation, else false.\n\t */\n\tpublic boolean isTaskStartup() {\n\t\treturn this.isTaskStartup;\n\t}\n\n\t/**\n\t * Indicates if the task listener was called during task end.\n\t * @return true if the task listener was called during task end, else false.\n\t */\n\tpublic boolean isTaskEnd() {\n\t\treturn this.isTaskEnd;\n\t}\n\n\t/**\n\t * Indicates if the task listener was called during task failed step.\n\t * @return true if task listener was called during task failure, else false.\n\t */\n\tpublic boolean isTaskFailed() {\n\t\treturn this.isTaskFailed;\n\t}\n\n\t/**\n\t * Task Execution that was updated during listener call.\n\t * @return instance of TaskExecution.\n\t */\n\tpublic TaskExecution getTaskExecution() {\n\t\treturn this.taskExecution;\n\t}\n\n\t/**\n\t * The throwable that was sent with the task if task failed.\n\t * @return instance of Throwable.\n\t */\n\tpublic Throwable getThrowable() {\n\t\treturn this.throwable;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestVerifierUtils.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.util;\n\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.Set;\nimport java.util.UUID;\n\nimport ch.qos.logback.classic.spi.LoggingEvent;\nimport ch.qos.logback.core.Appender;\nimport org.mockito.ArgumentMatcher;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.cloud.task.repository.TaskExecution;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n/**\n * Offers utils to test the results produced by the code being tested.\n *\n * @author Glenn Renfro\n */\npublic final class TestVerifierUtils {\n\n\t/**\n\t * The default number of arguments to use for the test TaskExecutions.\n\t */\n\tpublic static final int ARG_SIZE = 5;\n\n\tprivate TestVerifierUtils() {\n\t}\n\n\t/**\n\t * Creates a mock {@link Appender} to be added to the root logger.\n\t * @return reference to the mock appender.\n\t */\n\tpublic static Appender getMockAppender() {\n\t\tch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory\n\t\t\t.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);\n\t\tfinal Appender mockAppender = mock(Appender.class);\n\t\twhen(mockAppender.getName()).thenReturn(\"MOCK\");\n\t\troot.addAppender(mockAppender);\n\t\treturn mockAppender;\n\t}\n\n\t/**\n\t * Verifies that the log sample is contained within the content that was written to\n\t * the mock appender.\n\t * @param mockAppender The appender that is associated with the test.\n\t * @param logSample The string to search for in the log entry.\n\t */\n\tpublic static void verifyLogEntryExists(Appender mockAppender, final String logSample) {\n\t\tverify(mockAppender).doAppend(argThat(new ArgumentMatcher() {\n\t\t\t@Override\n\t\t\tpublic boolean matches(final Object argument) {\n\t\t\t\treturn ((LoggingEvent) argument).getFormattedMessage().contains(logSample);\n\t\t\t}\n\t\t}));\n\t}\n\n\t/**\n\t * Creates a fully populated TaskExecution (except args) for testing.\n\t * @return instance of a TaskExecution\n\t */\n\tpublic static TaskExecution createSampleTaskExecutionNoArg() {\n\t\tRandom randomGenerator = new Random();\n\t\tlong executionId = randomGenerator.nextLong();\n\t\tString taskName = UUID.randomUUID().toString();\n\n\t\treturn new TaskExecution(executionId, null, taskName, LocalDateTime.now(), null, null, new ArrayList<>(), null,\n\t\t\t\tnull);\n\t}\n\n\t/**\n\t * Creates a fully populated TaskExecution (except args) for testing.\n\t * @return instance of a TaskExecution.\n\t */\n\tpublic static TaskExecution endSampleTaskExecutionNoArg() {\n\t\tRandom randomGenerator = new Random();\n\t\tint exitCode = randomGenerator.nextInt();\n\t\tlong executionId = randomGenerator.nextLong();\n\t\tString taskName = UUID.randomUUID().toString();\n\t\tString exitMessage = UUID.randomUUID().toString();\n\n\t\treturn new TaskExecution(executionId, exitCode, taskName, LocalDateTime.now(), LocalDateTime.now(), exitMessage,\n\t\t\t\tnew ArrayList<>(), null, null);\n\t}\n\n\t/**\n\t * Creates a fully populated TaskExecution for testing.\n\t * @param executionId the taskExecutionId to be created.\n\t * @return instance of the TaskExecution.\n\t */\n\tpublic static TaskExecution createSampleTaskExecution(long executionId) {\n\t\tString taskName = UUID.randomUUID().toString();\n\t\tString externalExecutionId = UUID.randomUUID().toString();\n\t\tList<String> args = new ArrayList<>(ARG_SIZE);\n\t\tfor (int i = 0; i < ARG_SIZE; i++) {\n\t\t\targs.add(UUID.randomUUID().toString());\n\t\t}\n\t\treturn new TaskExecution(executionId, null, taskName, LocalDateTime.now(), null, null, args, null,\n\t\t\t\texternalExecutionId);\n\t}\n\n\t/**\n\t * Verifies that all the fields in between the expected and actual are the same.\n\t * @param expectedTaskExecution The expected value for the task execution.\n\t * @param actualTaskExecution The actual value for the task execution.\n\t */\n\tpublic static void verifyTaskExecution(TaskExecution expectedTaskExecution, TaskExecution actualTaskExecution) {\n\t\tassertThat(actualTaskExecution.getExecutionId()).as(\"taskExecutionId must be equal\")\n\t\t\t.isEqualTo(expectedTaskExecution.getExecutionId());\n\t\tif (actualTaskExecution.getStartTime() != null) {\n\t\t\tassertThat(actualTaskExecution.getStartTime().getHour() == expectedTaskExecution.getStartTime().getHour())\n\t\t\t\t.as(\"startTime hour must be equal\")\n\t\t\t\t.isTrue();\n\t\t\tassertThat(\n\t\t\t\t\tactualTaskExecution.getStartTime().getMinute() == expectedTaskExecution.getStartTime().getMinute())\n\t\t\t\t.as(\"startTime minute must be equal\")\n\t\t\t\t.isTrue();\n\t\t\tassertThat(\n\t\t\t\t\tactualTaskExecution.getStartTime().getSecond() == expectedTaskExecution.getStartTime().getSecond())\n\t\t\t\t.as(\"startTime second must be equal\")\n\t\t\t\t.isTrue();\n\t\t\tassertThat(actualTaskExecution.getStartTime().getDayOfYear() == expectedTaskExecution.getStartTime()\n\t\t\t\t.getDayOfYear()).as(\"startTime day must be equal\").isTrue();\n\t\t\tassertThat(actualTaskExecution.getStartTime().getYear() == expectedTaskExecution.getStartTime().getYear())\n\t\t\t\t.as(\"startTime year must be equal\")\n\t\t\t\t.isTrue();\n\t\t\tassertThat(actualTaskExecution.getStartTime().getMonthValue() == expectedTaskExecution.getStartTime()\n\t\t\t\t.getMonthValue()).as(\"startTime month must be equal\").isTrue();\n\t\t}\n\t\tif (actualTaskExecution.getEndTime() != null) {\n\t\t\tassertThat(actualTaskExecution.getEndTime().getHour() == expectedTaskExecution.getEndTime().getHour())\n\t\t\t\t.as(\"endTime hour must be equal\")\n\t\t\t\t.isTrue();\n\t\t\tassertThat(actualTaskExecution.getEndTime().getMinute() == expectedTaskExecution.getEndTime().getMinute())\n\t\t\t\t.as(\"endTime minute must be equal\")\n\t\t\t\t.isTrue();\n\t\t\tassertThat(actualTaskExecution.getEndTime().getSecond() == expectedTaskExecution.getEndTime().getSecond())\n\t\t\t\t.as(\"endTime second must be equal\")\n\t\t\t\t.isTrue();\n\t\t\tassertThat(actualTaskExecution.getEndTime().getDayOfYear() == expectedTaskExecution.getEndTime()\n\t\t\t\t.getDayOfYear()).as(\"endTime day must be equal\").isTrue();\n\t\t\tassertThat(actualTaskExecution.getEndTime().getYear() == expectedTaskExecution.getEndTime().getYear())\n\t\t\t\t.as(\"endTime year must be equal\")\n\t\t\t\t.isTrue();\n\t\t\tassertThat(actualTaskExecution.getEndTime().getMonthValue() == expectedTaskExecution.getEndTime()\n\t\t\t\t.getMonthValue()).as(\"endTime month must be equal\").isTrue();\n\t\t}\n\t\tassertThat(actualTaskExecution.getExitCode()).as(\"exitCode must be equal\")\n\t\t\t.isEqualTo(expectedTaskExecution.getExitCode());\n\t\tassertThat(actualTaskExecution.getTaskName()).as(\"taskName must be equal\")\n\t\t\t.isEqualTo(expectedTaskExecution.getTaskName());\n\t\tassertThat(actualTaskExecution.getExitMessage()).as(\"exitMessage must be equal\")\n\t\t\t.isEqualTo(expectedTaskExecution.getExitMessage());\n\t\tassertThat(actualTaskExecution.getErrorMessage()).as(\"errorMessage must be equal\")\n\t\t\t.isEqualTo(expectedTaskExecution.getErrorMessage());\n\t\tassertThat(actualTaskExecution.getExternalExecutionId()).as(\"externalExecutionId must be equal\")\n\t\t\t.isEqualTo(expectedTaskExecution.getExternalExecutionId());\n\t\tassertThat(actualTaskExecution.getParentExecutionId()).as(\"parentExecutionId must be equal\")\n\t\t\t.isEqualTo(expectedTaskExecution.getParentExecutionId());\n\n\t\tif (expectedTaskExecution.getArguments() != null) {\n\t\t\tassertThat(actualTaskExecution.getArguments()).as(\"arguments should not be null\").isNotNull();\n\t\t\tassertThat(actualTaskExecution.getArguments().size())\n\t\t\t\t.as(\"arguments result set count should match expected count\")\n\t\t\t\t.isEqualTo(expectedTaskExecution.getArguments().size());\n\t\t}\n\t\telse {\n\t\t\tassertThat(actualTaskExecution.getArguments()).as(\"arguments should be null\").isNull();\n\t\t}\n\t\tSet<String> args = new HashSet<>();\n\t\tfor (String param : expectedTaskExecution.getArguments()) {\n\t\t\targs.add(param);\n\t\t}\n\t\tfor (String arg : actualTaskExecution.getArguments()) {\n\t\t\tassertThat(args.contains(arg)).as(\"arg must exist in the repository\").isTrue();\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/resources/application.properties",
    "content": "logging.level.org.springframework.cloud.task=debug\n"
  },
  {
    "path": "spring-cloud-task-core/src/test/resources/micrometer/pcf-scs-info.json",
    "content": "{\n  \"sso\":[{\n    \"name\": \"sso\",\n    \"label\": \"sso\",\n    \"plan\": \"notfree\",\n    \"tags\": [\"configuration\"],\n    \"credentials\":{\n      \"uri\": \"https://pivotal.io\",\n      \"client_id\": \"fakeClientId\",\n      \"client_secret\": \"fakeSecret\",\n      \"access_token_uri\": \"token\"\n    }\n  }]}\n"
  },
  {
    "path": "spring-cloud-task-dependencies/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t<version>5.0.2-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<name>Spring Cloud Task Dependencies</name>\n\t<description>Spring Cloud Task Dependencies</description>\n\n\t<parent>\n\t\t<artifactId>spring-cloud-dependencies-parent</artifactId>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<version>5.0.2-SNAPSHOT</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-starter-task</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-core</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-batch</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-stream</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>spring</id>\n\t\t\t<repositories>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>spring-snapshots</id>\n\t\t\t\t\t<name>Spring Snapshots</name>\n\t\t\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>spring-milestones</id>\n\t\t\t\t\t<name>Spring Milestones</name>\n\t\t\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t\t<repository>\n\t\t\t\t\t<id>spring-releases</id>\n\t\t\t\t\t<name>Spring Releases</name>\n\t\t\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</repository>\n\t\t\t</repositories>\n\t\t\t<pluginRepositories>\n\t\t\t\t<pluginRepository>\n\t\t\t\t\t<id>spring-snapshots</id>\n\t\t\t\t\t<name>Spring Snapshots</name>\n\t\t\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>true</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</pluginRepository>\n\t\t\t\t<pluginRepository>\n\t\t\t\t\t<id>spring-milestones</id>\n\t\t\t\t\t<name>Spring Milestones</name>\n\t\t\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t\t\t<snapshots>\n\t\t\t\t\t\t<enabled>false</enabled>\n\t\t\t\t\t</snapshots>\n\t\t\t\t</pluginRepository>\n\t\t\t</pluginRepositories>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<parent>\n\t\t<artifactId>spring-cloud-task-parent</artifactId>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<version>5.0.2-SNAPSHOT</version>\n\t</parent>\n\t<modelVersion>4.0.0</modelVersion>\n\t<name>Spring Cloud Task Integration Tests</name>\n\t<description>Tests the integration between Task/Batch Events and Stream Binders\n\t</description>\n\t<groupId>org.springframework.cloud</groupId>\n\t<artifactId>spring-cloud-task-integration-tests</artifactId>\n\n\t<properties>\n\t\t<spring-cloud-commons.version>5.0.2-SNAPSHOT</spring-cloud-commons.version>\n\t</properties>\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-task-stream</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-stream-rabbit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-stream-binder-rabbit-test-support</artifactId>\n\t\t\t<version>${spring-cloud-stream-binder-rabbit.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.batch</groupId>\n\t\t\t<artifactId>spring-batch-core</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-task-batch</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-test-support</artifactId>\n\t\t\t<version>${spring-cloud-commons.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.integration</groupId>\n\t\t\t<artifactId>spring-integration-core</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.integration</groupId>\n\t\t\t<artifactId>spring-integration-jdbc</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers-junit-jupiter</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers-rabbitmq</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers-db2</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-stream-test-binder</artifactId>\n\t\t\t<version>${spring-cloud-stream.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-stream</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.integration</groupId>\n\t\t\t<artifactId>spring-integration-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers-mariadb</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mariadb.jdbc</groupId>\n\t\t\t<artifactId>mariadb-java-client</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<!--skip deploy (this is just a test module) -->\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>integrationTests</id>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t\t\t<version>2.22.2</version>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<skipTests>false</skipTests>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>skipIntegrationTests</id>\n\t\t\t<activation>\n\t\t\t\t<activeByDefault>true</activeByDefault>\n\t\t\t</activation>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t\t\t<version>2.22.2</version>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<skipTests>true</skipTests>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/java/configuration/JobConfiguration.java",
    "content": "/*\n * Copyright 2021-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage configuration;\n\nimport java.util.Arrays;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.scope.context.ChunkContext;\nimport org.springframework.batch.core.step.Step;\nimport org.springframework.batch.core.step.StepContribution;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.core.step.tasklet.Tasklet;\nimport org.springframework.batch.infrastructure.item.Chunk;\nimport org.springframework.batch.infrastructure.item.ItemProcessor;\nimport org.springframework.batch.infrastructure.item.ItemWriter;\nimport org.springframework.batch.infrastructure.item.support.ListItemReader;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * @author Glenn Renfro\n */\n@Configuration\n@ConditionalOnProperty(prefix = \"spring.cloud.task.test\", name = \"enable-job-configuration\", havingValue = \"true\")\npublic class JobConfiguration {\n\n\tprivate static final int DEFAULT_CHUNK_COUNT = 3;\n\n\t@Autowired\n\tprivate JobRepository jobRepository;\n\n\t@Autowired\n\tprivate PlatformTransactionManager transactionManager;\n\n\t@Bean\n\tpublic Job job() {\n\t\treturn new JobBuilder(\"job\", this.jobRepository).start(step1()).next(step2()).build();\n\t}\n\n\t@Bean\n\tpublic Step step1() {\n\t\treturn new StepBuilder(\"step1\", this.jobRepository).tasklet(new Tasklet() {\n\t\t\t@Override\n\t\t\tpublic RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {\n\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t}\n\t\t}, transactionManager).build();\n\t}\n\n\t@Bean\n\tpublic Step step2() {\n\t\treturn new StepBuilder(\"step2\", this.jobRepository)\n\t\t\t.<String, String>chunk(DEFAULT_CHUNK_COUNT, transactionManager)\n\t\t\t.reader(new ListItemReader<>(Arrays.asList(\"1\", \"2\", \"3\", \"4\", \"5\", \"6\")))\n\t\t\t.processor(new ItemProcessor<String, String>() {\n\t\t\t\t@Override\n\t\t\t\tpublic String process(String item) throws Exception {\n\t\t\t\t\treturn String.valueOf(Integer.parseInt(item) * -1);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.writer(new ItemWriter<String>() {\n\t\t\t\t@Override\n\t\t\t\tpublic void write(Chunk<? extends String> items) throws Exception {\n\t\t\t\t\tfor (Object item : items) {\n\t\t\t\t\t\tSystem.out.println(\">> \" + item);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/java/configuration/JobSkipConfiguration.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage configuration;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.scope.context.ChunkContext;\nimport org.springframework.batch.core.step.Step;\nimport org.springframework.batch.core.step.StepContribution;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.core.step.tasklet.Tasklet;\nimport org.springframework.batch.infrastructure.item.ItemProcessor;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * @author Glenn Renfro\n */\n@Configuration\n@ConditionalOnProperty(prefix = \"spring.cloud.task.test\", name = \"enable-fail-job-configuration\")\npublic class JobSkipConfiguration {\n\n\t@Autowired\n\tprivate JobRepository jobRepository;\n\n\t@Autowired\n\tprivate PlatformTransactionManager transactionManager;\n\n\t@Bean\n\tpublic Job job() {\n\t\treturn new JobBuilder(\"job\", this.jobRepository).start(step1()).next(step2()).build();\n\t}\n\n\t@Bean\n\tpublic Step step1() {\n\t\treturn new StepBuilder(\"step1\", this.jobRepository).tasklet(new Tasklet() {\n\t\t\t@Override\n\t\t\tpublic RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {\n\t\t\t\tSystem.out.println(\"Executed\");\n\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t}\n\t\t}, transactionManager).build();\n\t}\n\n\t@Bean\n\tpublic Step step2() {\n\t\treturn new StepBuilder(\"step2\", this.jobRepository).chunk(3, transactionManager)\n\t\t\t.faultTolerant()\n\t\t\t.skip(IllegalStateException.class)\n\t\t\t.skipLimit(100)\n\t\t\t.reader(new SkipItemReader())\n\t\t\t.processor(new ItemProcessor<Object, Object>() {\n\t\t\t\t@Override\n\t\t\t\tpublic String process(Object item) throws Exception {\n\t\t\t\t\treturn String.valueOf(Integer.parseInt((String) item) * -1);\n\t\t\t\t}\n\t\t\t})\n\t\t\t.writer(new SkipItemWriter())\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/java/configuration/SkipItemReader.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage configuration;\n\nimport org.springframework.batch.infrastructure.item.ItemReader;\nimport org.springframework.batch.infrastructure.item.NonTransientResourceException;\nimport org.springframework.batch.infrastructure.item.ParseException;\nimport org.springframework.batch.infrastructure.item.UnexpectedInputException;\n\n/**\n * @author Glenn Renfro\n */\npublic class SkipItemReader implements ItemReader {\n\n\tint failCount = 0;\n\n\tboolean finished = false;\n\n\t@Override\n\tpublic Object read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {\n\t\tString result = \"1\";\n\t\tif (this.failCount < 2) {\n\t\t\tthis.failCount++;\n\t\t\tthrow new IllegalStateException(\"Reader FOOBAR\");\n\t\t}\n\t\tif (this.finished) {\n\t\t\tresult = null;\n\t\t}\n\t\tthis.finished = true;\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/java/configuration/SkipItemWriter.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage configuration;\n\nimport org.springframework.batch.infrastructure.item.Chunk;\nimport org.springframework.batch.infrastructure.item.ItemWriter;\n\n/**\n * @author Glenn Renfro\n */\npublic class SkipItemWriter implements ItemWriter {\n\n\tint failCount = 0;\n\n\t@Override\n\tpublic void write(Chunk items) throws Exception {\n\t\tif (this.failCount < 2) {\n\t\t\tthis.failCount++;\n\t\t\tthrow new IllegalStateException(\"Writer FOOBAR\");\n\t\t}\n\t\tfor (Object item : items) {\n\t\t\tSystem.out.println(\">> \" + item);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/executionid/TaskStartApplication.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.executionid;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * @author Glenn Renfro\n */\n@EnableTask\n@SpringBootApplication\npublic class TaskStartApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(TaskStartApplication.class, args);\n\t}\n\n\t@Bean\n\tpublic CommandLineRunner testCommandLineRunner() {\n\t\treturn new CommandLineRunner() {\n\t\t\t@Override\n\t\t\tpublic void run(String... strings) throws Exception {\n\t\t\t\tfor (String s : strings) {\n\t\t\t\t\tSystem.out.println(\"Test\" + s);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/executionid/TaskStartTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.executionid;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mariadb.MariaDBContainer;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.TaskRepository;\nimport org.springframework.cloud.task.repository.support.SimpleTaskExplorer;\nimport org.springframework.cloud.task.repository.support.SimpleTaskRepository;\nimport org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.core.simple.SimpleJdbcInsert;\nimport org.springframework.jdbc.datasource.DriverManagerDataSource;\nimport org.springframework.jdbc.datasource.init.DataSourceInitializer;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n@Testcontainers\npublic class TaskStartTests {\n\n\tprivate final static int WAIT_INTERVAL = 500;\n\n\tprivate final static int MAX_WAIT_TIME = 5000;\n\n\tprivate final static String TASK_NAME = \"TASK_LAUNCHER_SINK_TEST\";\n\n\tprivate static final DockerImageName MARIADB_IMAGE = DockerImageName.parse(\"mariadb:10.9.3\");\n\n\t/**\n\t * Provide mariadb test container for tests.\n\t */\n\t@Container\n\tpublic static MariaDBContainer mariaDBContainer = new MariaDBContainer(MARIADB_IMAGE);\n\n\tprivate DataSource dataSource;\n\n\tprivate Map<String, String> properties;\n\n\tprivate TaskExplorer taskExplorer;\n\n\tprivate TaskRepository taskRepository;\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@BeforeEach\n\tpublic void setup() {\n\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\tdataSource.setDriverClassName(mariaDBContainer.getDriverClassName());\n\t\tdataSource.setUrl(mariaDBContainer.getJdbcUrl());\n\t\tdataSource.setUsername(mariaDBContainer.getUsername());\n\t\tdataSource.setPassword(mariaDBContainer.getPassword());\n\t\tthis.dataSource = dataSource;\n\t\tTaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(dataSource);\n\t\tthis.taskExplorer = new SimpleTaskExplorer(factoryBean);\n\t\tthis.taskRepository = new SimpleTaskRepository(factoryBean);\n\n\t\tthis.properties = new HashMap<>();\n\t\tthis.properties.put(\"spring.datasource.url\", mariaDBContainer.getJdbcUrl());\n\t\tthis.properties.put(\"spring.datasource.username\", mariaDBContainer.getUsername());\n\t\tthis.properties.put(\"spring.datasource.password\", mariaDBContainer.getPassword());\n\t\tthis.properties.put(\"spring.datasource.driverClassName\", mariaDBContainer.getDriverClassName());\n\t\tthis.properties.put(\"spring.application.name\", TASK_NAME);\n\t\tthis.properties.put(\"spring.cloud.task.initialize-enabled\", \"false\");\n\n\t\tJdbcTemplate template = new JdbcTemplate(this.dataSource);\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS TASK_TASK_BATCH\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS TASK_SEQ\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS TASK_EXECUTION_PARAMS\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS TASK_EXECUTION\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS TASK_LOCK\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_SEQ\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_CONTEXT\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_STEP_EXECUTION\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_SEQ\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_SEQ\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_PARAMS\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_CONTEXT\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_EXECUTION\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_INSTANCE\");\n\t\ttemplate.execute(\"DROP SEQUENCE IF EXISTS TASK_SEQ\");\n\n\t\tDataSourceInitializer initializer = new DataSourceInitializer();\n\n\t\tinitializer.setDataSource(this.dataSource);\n\t\tResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();\n\t\tdatabasePopulator.addScript(new ClassPathResource(\"/org/springframework/cloud/task/schema-mariadb.sql\"));\n\t\tinitializer.setDatabasePopulator(databasePopulator);\n\t\tinitializer.afterPropertiesSet();\n\t}\n\n\t@Test\n\tpublic void testWithGeneratedTaskExecution() throws Exception {\n\t\tthis.taskRepository.createTaskExecution();\n\t\tassertThat(this.taskExplorer.getTaskExecutionCount()).as(\"Only one row is expected\").isEqualTo(1);\n\t\tthis.applicationContext = getTaskApplication(1).run(new String[0]);\n\t\tassertThat(waitForDBToBePopulated()).isTrue();\n\n\t\tPage<TaskExecution> taskExecutions = this.taskExplorer.findAll(PageRequest.of(0, 10));\n\t\tTaskExecution te = taskExecutions.iterator().next();\n\t\tassertThat(taskExecutions.getTotalElements()).as(\"Only one row is expected\").isEqualTo(1);\n\t\tassertThat(taskExecutions.iterator().next().getExitCode().intValue()).as(\"return code should be 0\")\n\t\t\t.isEqualTo(0);\n\t}\n\n\t@Test\n\tpublic void testWithGeneratedTaskExecutionWithName() throws Exception {\n\t\tfinal String TASK_EXECUTION_NAME = \"PRE-EXECUTION-TEST-NAME\";\n\t\tthis.taskRepository.createTaskExecution(TASK_EXECUTION_NAME);\n\t\tassertThat(this.taskExplorer.getTaskExecutionCount()).as(\"Only one row is expected\").isEqualTo(1);\n\t\tassertThat(this.taskExplorer.getTaskExecution(1).getTaskName()).isEqualTo(TASK_EXECUTION_NAME);\n\n\t\tthis.applicationContext = getTaskApplication(1).run(new String[0]);\n\t\tassertThat(waitForDBToBePopulated()).isTrue();\n\n\t\tPage<TaskExecution> taskExecutions = this.taskExplorer.findAll(PageRequest.of(0, 10));\n\t\tTaskExecution te = taskExecutions.iterator().next();\n\t\tassertThat(taskExecutions.getTotalElements()).as(\"Only one row is expected\").isEqualTo(1);\n\t\tassertThat(taskExecutions.iterator().next().getExitCode().intValue()).as(\"return code should be 0\")\n\t\t\t.isEqualTo(0);\n\t\tassertThat(this.taskExplorer.getTaskExecution(1).getTaskName()).isEqualTo(\"batchEvents\");\n\t}\n\n\t@Test\n\tpublic void testWithGeneratedTaskExecutionWithExistingDate() throws Exception {\n\t\tfinal String TASK_EXECUTION_NAME = \"PRE-EXECUTION-TEST-NAME\";\n\t\tLocalDateTime startDate = LocalDateTime.now();\n\t\tThread.sleep(500);\n\t\tTaskExecution taskExecution = new TaskExecution(1, 0, TASK_EXECUTION_NAME, startDate, LocalDateTime.now(),\n\t\t\t\t\"foo\", Collections.emptyList(), \"foo\", \"bar\", null);\n\t\tthis.taskRepository.createTaskExecution(taskExecution);\n\t\tassertThat(this.taskExplorer.getTaskExecutionCount()).as(\"Only one row is expected\").isEqualTo(1);\n\n\t\tthis.applicationContext = getTaskApplication(1).run(new String[0]);\n\t\tassertThat(waitForDBToBePopulated()).isTrue();\n\n\t\tPage<TaskExecution> taskExecutions = this.taskExplorer.findAll(PageRequest.of(0, 10));\n\t\tassertThat(taskExecutions.getTotalElements()).as(\"Only one row is expected\").isEqualTo(1);\n\t\tassertThat(taskExecutions.iterator().next().getExitCode().intValue()).as(\"return code should be 0\")\n\t\t\t.isEqualTo(0);\n\t\tassertThat(this.taskExplorer.getTaskExecution(1).getStartTime().isEqual(startDate)).isTrue();\n\n\t}\n\n\t@Test\n\tpublic void testWithNoTaskExecution() throws Exception {\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(() -> {\n\t\t\tthis.applicationContext = getTaskApplication(55).run(new String[0]);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testCompletedTaskExecution() throws Exception {\n\t\tthis.taskRepository.createTaskExecution();\n\t\tassertThat(this.taskExplorer.getTaskExecutionCount()).as(\"Only one row is expected\").isEqualTo(1);\n\t\tthis.taskRepository.completeTaskExecution(1, 0, LocalDateTime.now(), \"\");\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(() -> {\n\t\t\tthis.applicationContext = getTaskApplication(1).run(new String[0]);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testDuplicateTaskExecutionWithSingleInstanceEnabled() throws Exception {\n\t\tString[] params = { \"--spring.cloud.task.single-instance-enabled=true\", \"--spring.cloud.task.name=foo\" };\n\t\tboolean testFailed = false;\n\t\ttry {\n\t\t\tthis.taskRepository.createTaskExecution();\n\t\t\tassertThat(this.taskExplorer.getTaskExecutionCount()).as(\"Only one row is expected\").isEqualTo(1);\n\t\t\tenableLock(\"foo\");\n\t\t\tgetTaskApplication(1).run(params);\n\t\t}\n\t\tcatch (ApplicationContextException taskException) {\n\t\t\tassertThat(taskException.getCause().getMessage()).isEqualTo(\"Failed to process \"\n\t\t\t\t\t+ \"@BeforeTask or @AfterTask annotation because: Task with name \\\"foo\\\" is already running.\");\n\t\t\ttestFailed = true;\n\t\t}\n\t\tassertThat(testFailed)\n\t\t\t.as(\"Expected TaskExecutionException for because  of \" + \"single-instance-enabled is enabled\")\n\t\t\t.isTrue();\n\n\t}\n\n\t@Test\n\tpublic void testDuplicateTaskExecutionWithSingleInstanceDisabled() throws Exception {\n\t\tthis.taskRepository.createTaskExecution();\n\t\tTaskExecution execution = this.taskRepository.createTaskExecution();\n\t\tthis.taskRepository.startTaskExecution(execution.getExecutionId(), \"bar\", LocalDateTime.now(),\n\t\t\t\tnew ArrayList<>(), \"\");\n\t\tString[] params = { \"--spring.cloud.task.name=bar\" };\n\t\tenableLock(\"bar\");\n\t\tthis.applicationContext = getTaskApplication(1).run(params);\n\t\tassertThat(waitForDBToBePopulated()).isTrue();\n\t}\n\n\tprivate SpringApplication getTaskApplication(Integer executionId) {\n\t\tSpringApplication myapp = new SpringApplication(TaskStartApplication.class);\n\t\tMap<String, Object> myMap = new HashMap<>();\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tmyMap.put(\"spring.cloud.task.executionid\", executionId);\n\t\tmyMap.put(\"spring.datasource.url\", mariaDBContainer.getJdbcUrl());\n\t\tmyMap.put(\"spring.datasource.username\", mariaDBContainer.getUsername());\n\t\tmyMap.put(\"spring.datasource.password\", mariaDBContainer.getPassword());\n\t\tmyMap.put(\"spring.datasource.driverClassName\", mariaDBContainer.getDriverClassName());\n\n\t\tpropertySources.addFirst(new MapPropertySource(\"EnvrionmentTestPropsource\", myMap));\n\t\tmyapp.setEnvironment(environment);\n\t\treturn myapp;\n\t}\n\n\tprivate boolean tableExists() throws SQLException {\n\t\tboolean result;\n\t\ttry (Connection conn = this.dataSource.getConnection();\n\t\t\t\tResultSet res = conn.getMetaData().getTables(null, null, \"TASK_EXECUTION\", new String[] { \"TABLE\" })) {\n\t\t\tresult = res.next();\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate boolean waitForDBToBePopulated() throws Exception {\n\t\tboolean isDbPopulated = false;\n\t\tfor (int waitTime = 0; waitTime <= MAX_WAIT_TIME; waitTime += WAIT_INTERVAL) {\n\t\t\tThread.sleep(WAIT_INTERVAL);\n\t\t\tif (tableExists() && this.taskExplorer.getTaskExecutionCount() > 0) {\n\t\t\t\tisDbPopulated = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn isDbPopulated;\n\t}\n\n\tprivate void enableLock(String lockKey) {\n\t\tSimpleJdbcInsert taskLockInsert = new SimpleJdbcInsert(this.dataSource).withTableName(\"TASK_LOCK\");\n\t\tMap<String, Object> taskLockParams = new HashMap<>();\n\t\ttaskLockParams.put(\"LOCK_KEY\", UUID.nameUUIDFromBytes(lockKey.getBytes()).toString());\n\t\ttaskLockParams.put(\"REGION\", \"DEFAULT\");\n\t\ttaskLockParams.put(\"CLIENT_ID\", \"aClientID\");\n\t\ttaskLockParams.put(\"CREATED_DATE\", LocalDateTime.now());\n\t\ttaskLockInsert.execute(taskLockParams);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/initializer/TaskInitializerTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.initializer;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.testcontainers.junit.jupiter.Container;\nimport org.testcontainers.junit.jupiter.Testcontainers;\nimport org.testcontainers.mariadb.MariaDBContainer;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.cloud.task.executionid.TaskStartApplication;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.cloud.task.repository.TaskExplorer;\nimport org.springframework.cloud.task.repository.support.SimpleTaskExplorer;\nimport org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean;\nimport org.springframework.context.ApplicationContextException;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.env.ConfigurableEnvironment;\nimport org.springframework.core.env.MapPropertySource;\nimport org.springframework.core.env.MutablePropertySources;\nimport org.springframework.core.env.StandardEnvironment;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.DriverManagerDataSource;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n@Testcontainers\npublic class TaskInitializerTests {\n\n\tprivate final static int WAIT_INTERVAL = 500;\n\n\tprivate final static int MAX_WAIT_TIME = 5000;\n\n\tprivate DataSource dataSource;\n\n\tprivate TaskExplorer taskExplorer;\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\tprivate static final DockerImageName MARIADB_IMAGE = DockerImageName.parse(\"mariadb:10.9.3\");\n\n\t/**\n\t * Provide mariadb test container for tests.\n\t */\n\t@Container\n\tpublic static MariaDBContainer mariaDBContainer = new MariaDBContainer(MARIADB_IMAGE);\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Autowired\n\tpublic void setDataSource(DataSource dataSource) {\n\t\tthis.dataSource = dataSource;\n\t\tTaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(dataSource);\n\t\tthis.taskExplorer = new SimpleTaskExplorer(factoryBean);\n\t}\n\n\t@BeforeEach\n\tpublic void setup() {\n\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\tdataSource.setDriverClassName(mariaDBContainer.getDriverClassName());\n\t\tdataSource.setUrl(mariaDBContainer.getJdbcUrl());\n\t\tdataSource.setUsername(mariaDBContainer.getUsername());\n\t\tdataSource.setPassword(mariaDBContainer.getPassword());\n\t\tthis.dataSource = dataSource;\n\t\tTaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(dataSource);\n\t\tthis.taskExplorer = new SimpleTaskExplorer(factoryBean);\n\n\t\tJdbcTemplate template = new JdbcTemplate(this.dataSource);\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS TASK_TASK_BATCH\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS TASK_SEQ\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS TASK_EXECUTION_PARAMS\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS TASK_EXECUTION\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS TASK_LOCK\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_SEQ\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_CONTEXT\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_STEP_EXECUTION\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_SEQ\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_SEQ\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_PARAMS\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_CONTEXT\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_EXECUTION\");\n\t\ttemplate.execute(\"DROP TABLE IF EXISTS BATCH_JOB_INSTANCE\");\n\t\ttemplate.execute(\"DROP SEQUENCE IF EXISTS TASK_SEQ\");\n\t}\n\n\t@Test\n\tpublic void testNotInitialized() throws Exception {\n\t\tSpringApplication myapp = getTaskApplication();\n\t\tString[] properties = { \"--spring.cloud.task.initialize-enabled=false\" };\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(() -> {\n\t\t\tthis.applicationContext = myapp.run(properties);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testWithInitialized() throws Exception {\n\t\tSpringApplication myapp = getTaskApplication();\n\t\tString[] properties = { \"--spring.cloud.task.initialize-enabled=true\" };\n\t\tthis.applicationContext = myapp.run(properties);\n\t\tassertThat(waitForDBToBePopulated()).isTrue();\n\n\t\tPage<TaskExecution> taskExecutions = this.taskExplorer.findAll(PageRequest.of(0, 10));\n\t\tTaskExecution te = taskExecutions.iterator().next();\n\t\tassertThat(taskExecutions.getTotalElements()).as(\"Only one row is expected\").isEqualTo(1);\n\t\tassertThat(taskExecutions.iterator().next().getExitCode().intValue()).as(\"return code should be 0\")\n\t\t\t.isEqualTo(0);\n\t}\n\n\t@Test\n\tpublic void testNotInitializedOriginalProperty() throws Exception {\n\t\tSpringApplication myapp = getTaskApplication();\n\t\tString[] properties = { \"--spring.cloud.task.initialize.enable=false\" };\n\t\tassertThatExceptionOfType(ApplicationContextException.class).isThrownBy(() -> {\n\t\t\tthis.applicationContext = myapp.run(properties);\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testWithInitializedOriginalProperty() throws Exception {\n\t\tSpringApplication myapp = getTaskApplication();\n\t\tString[] properties = { \"--spring.cloud.task.initialize.enable=true\" };\n\t\tthis.applicationContext = myapp.run(properties);\n\t\tassertThat(waitForDBToBePopulated()).isTrue();\n\n\t\tPage<TaskExecution> taskExecutions = this.taskExplorer.findAll(PageRequest.of(0, 10));\n\t\tTaskExecution te = taskExecutions.iterator().next();\n\t\tassertThat(taskExecutions.getTotalElements()).as(\"Only one row is expected\").isEqualTo(1);\n\t\tassertThat(taskExecutions.iterator().next().getExitCode().intValue()).as(\"return code should be 0\")\n\t\t\t.isEqualTo(0);\n\t}\n\n\tprivate boolean tableExists() throws SQLException {\n\t\tboolean result;\n\t\ttry (Connection conn = this.dataSource.getConnection();\n\t\t\t\tResultSet res = conn.getMetaData().getTables(null, null, \"TASK_EXECUTION\", new String[] { \"TABLE\" })) {\n\t\t\tresult = res.next();\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate boolean waitForDBToBePopulated() throws Exception {\n\t\tboolean isDbPopulated = false;\n\t\tfor (int waitTime = 0; waitTime <= MAX_WAIT_TIME; waitTime += WAIT_INTERVAL) {\n\t\t\tThread.sleep(WAIT_INTERVAL);\n\t\t\tif (tableExists() && this.taskExplorer.getTaskExecutionCount() > 0) {\n\t\t\t\tisDbPopulated = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn isDbPopulated;\n\t}\n\n\tprivate SpringApplication getTaskApplication() {\n\t\tSpringApplication myapp = new SpringApplication(TaskStartApplication.class);\n\t\tMap<String, Object> myMap = new HashMap<>();\n\t\tConfigurableEnvironment environment = new StandardEnvironment();\n\t\tMutablePropertySources propertySources = environment.getPropertySources();\n\t\tmyMap.put(\"spring.datasource.url\", mariaDBContainer.getJdbcUrl());\n\t\tmyMap.put(\"spring.datasource.username\", mariaDBContainer.getUsername());\n\t\tmyMap.put(\"spring.datasource.password\", mariaDBContainer.getPassword());\n\t\tmyMap.put(\"spring.datasource.driverClassName\", mariaDBContainer.getDriverClassName());\n\n\t\tpropertySources.addFirst(new MapPropertySource(\"EnvrionmentTestPropsource\", myMap));\n\t\tmyapp.setEnvironment(environment);\n\t\treturn myapp;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/listener/BatchExecutionEventTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\n\nimport configuration.JobConfiguration;\nimport configuration.JobSkipConfiguration;\nimport org.assertj.core.api.Assertions;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.DeserializationFeature;\nimport tools.jackson.databind.ObjectMapper;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.cloud.stream.binder.test.OutputDestination;\nimport org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;\nimport org.springframework.cloud.task.batch.listener.support.JobExecutionEvent;\nimport org.springframework.cloud.task.batch.listener.support.StepExecutionEvent;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.messaging.Message;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n */\npublic class BatchExecutionEventTests {\n\n\tprivate static final String TASK_NAME = \"taskEventTest\";\n\n\tprivate ObjectMapper objectMapper;\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\t@BeforeEach\n\tpublic void setup() {\n\t\tobjectMapper = JsonMapper.builder().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();\n\t}\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testContext() {\n\t\tthis.applicationContext = new SpringApplicationBuilder()\n\t\t\t.sources(TestChannelBinderConfiguration.getCompleteConfiguration(BatchEventsApplication.class))\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.build()\n\t\t\t.run(getCommandLineParams(\"--spring.cloud.stream.bindings.job-execution-events.destination=bazbar\"));\n\n\t\tassertThat(this.applicationContext.getBean(\"jobExecutionEventsListener\")).isNotNull();\n\t\tassertThat(this.applicationContext.getBean(\"stepExecutionEventsListener\")).isNotNull();\n\t\tassertThat(this.applicationContext.getBean(\"chunkEventsListener\")).isNotNull();\n\t\tassertThat(this.applicationContext.getBean(\"itemReadEventsListener\")).isNotNull();\n\t\tassertThat(this.applicationContext.getBean(\"itemWriteEventsListener\")).isNotNull();\n\t\tassertThat(this.applicationContext.getBean(\"itemProcessEventsListener\")).isNotNull();\n\t\tassertThat(this.applicationContext.getBean(\"skipEventsListener\")).isNotNull();\n\t}\n\n\t@Test\n\tpublic void testJobEventListener() throws Exception {\n\t\tList<Message<byte[]>> result = testListener(\n\t\t\t\t\"--spring.cloud.task.batch.events.jobExecutionEventBindingName=foobar\", \"foobar\", 1);\n\t\tJobExecutionEvent jobExecutionEvent = this.objectMapper.readValue(result.get(0).getPayload(),\n\t\t\t\tJobExecutionEvent.class);\n\t\tAssertions.assertThat(jobExecutionEvent.getJobInstance().getJobName())\n\t\t\t.isEqualTo(\"job\")\n\t\t\t.as(\"Job name should be job\");\n\t}\n\n\t@Test\n\tpublic void testStepEventListener() throws Exception {\n\t\tfinal String bindingName = \"step-execution-foobar\";\n\t\tList<Message<byte[]>> result = testListener(\n\t\t\t\t\"--spring.cloud.task.batch.events.stepExecutionEventBindingName=\" + bindingName, bindingName, 4);\n\t\tint stepOneCount = 0;\n\t\tint stepTwoCount = 0;\n\t\tfor (int i = 0; i < 4; i++) {\n\t\t\tStepExecutionEvent stepExecutionEvent = this.objectMapper.readValue(result.get(i).getPayload(),\n\t\t\t\t\tStepExecutionEvent.class);\n\t\t\tif (stepExecutionEvent.getStepName().equals(\"step1\")) {\n\t\t\t\tstepOneCount++;\n\t\t\t}\n\t\t\tif (stepExecutionEvent.getStepName().equals(\"step2\")) {\n\t\t\t\tstepTwoCount++;\n\t\t\t}\n\t\t}\n\n\t\tassertThat(stepOneCount).as(\"the number of step1 events did not match\").isEqualTo(2);\n\t\tassertThat(stepTwoCount).as(\"the number of step2 events did not match\").isEqualTo(2);\n\n\t}\n\n\t@Test\n\tpublic void testItemProcessEventListener() {\n\t\tfinal String bindingName = \"item-execution-foobar\";\n\n\t\tList<Message<byte[]>> result = testListener(\n\t\t\t\t\"--spring.cloud.task.batch.events.itemProcessEventBindingName=\" + bindingName, bindingName, 1);\n\t\tString value = new String(result.get(0).getPayload());\n\t\tassertThat(value).isEqualTo(\"item did not equal result after processing\");\n\n\t}\n\n\t@Test\n\tpublic void testChunkListener() {\n\t\tfinal String bindingName = \"chunk-events-foobar\";\n\n\t\tList<Message<byte[]>> result = testListener(\n\t\t\t\t\"--spring.cloud.task.batch.events.chunkEventBindingName=\" + bindingName, bindingName, 2);\n\t\tString value = new String(result.get(0).getPayload());\n\t\tassertThat(value).isEqualTo(\"Before Chunk Processing\");\n\t\tvalue = new String(result.get(1).getPayload());\n\t\tassertThat(value).isEqualTo(\"After Chunk Processing\");\n\t}\n\n\t@Test\n\tpublic void testWriteListener() {\n\t\tfinal String bindingName = \"item-write-events-foobar\";\n\n\t\tList<Message<byte[]>> result = testListener(\n\t\t\t\t\"--spring.cloud.task.batch.events.itemWriteEventBindingName=\" + bindingName, bindingName, 2);\n\t\tString value = new String(result.get(0).getPayload());\n\t\tassertThat(value).isEqualTo(\"3 items to be written.\");\n\t\tvalue = new String(result.get(1).getPayload());\n\t\tassertThat(value).isEqualTo(\"3 items have been written.\");\n\t}\n\n\tprivate String[] getCommandLineParams(String sinkChannelParam) {\n\t\treturn getCommandLineParams(sinkChannelParam, true);\n\t}\n\n\tprivate String[] getCommandLineParams(String sinkChannelParam, boolean enableFailJobConfig) {\n\t\tString jobConfig = enableFailJobConfig ? \"--spring.cloud.task.test.enable-job-configuration=true\"\n\t\t\t\t: \"--spring.cloud.task.test.enable-fail-job-configuration=true\";\n\t\treturn new String[] { \"--spring.cloud.task.closecontext_enable=false\", \"--spring.cloud.task.name=\" + TASK_NAME,\n\t\t\t\t\"--spring.main.web-environment=false\", \"--spring.cloud.stream.defaultBinder=rabbit\",\n\t\t\t\t\"--spring.cloud.stream.bindings.task-events.destination=test\", jobConfig, \"foo=\" + UUID.randomUUID(),\n\t\t\t\tsinkChannelParam };\n\t}\n\n\tprivate List<Message<byte[]>> testListener(String channelBinding, String bindingName, int numberToRead) {\n\t\treturn testListenerForApp(channelBinding, bindingName, numberToRead, BatchEventsApplication.class, true);\n\t}\n\n\tprivate List<Message<byte[]>> testListenerSkip(String channelBinding, String bindingName, int numberToRead) {\n\t\treturn testListenerForApp(channelBinding, bindingName, numberToRead, BatchSkipEventsApplication.class, false);\n\t}\n\n\tprivate List<Message<byte[]>> testListenerForApp(String channelBinding, String bindingName, int numberToRead,\n\t\t\tClass clazz, boolean enableFailJobConfig) {\n\t\tList<Message<byte[]>> results = new ArrayList<>();\n\n\t\tthis.applicationContext = new SpringApplicationBuilder()\n\t\t\t.sources(TestChannelBinderConfiguration.getCompleteConfiguration(clazz))\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.build()\n\t\t\t.run(getCommandLineParams(channelBinding, enableFailJobConfig));\n\n\t\tOutputDestination target = this.applicationContext.getBean(OutputDestination.class);\n\n\t\tfor (int i = 0; i < numberToRead; i++) {\n\t\t\tresults.add(target.receive(10000, bindingName));\n\t\t}\n\t\treturn results;\n\t}\n\n\t@Test\n\tpublic void testItemReadListener() {\n\t\tfinal String bindingName = \"item-read-events-foobar\";\n\n\t\tList<Message<byte[]>> result = testListenerSkip(\n\t\t\t\t\"--spring.cloud.task.batch.events.itemReadEventBindingName=\" + bindingName, bindingName, 1);\n\t\tString exceptionMessage = new String(result.get(0).getPayload());\n\t\tassertThat(exceptionMessage).isEqualTo(\"Exception while item was being read\");\n\t}\n\n\t@Test\n\tpublic void testSkipEventListener() {\n\t\tfinal String SKIPPING_READ_MESSAGE = \"Skipped when reading.\";\n\n\t\tfinal String SKIPPING_WRITE_CONTENT = \"-1\";\n\t\tfinal String bindingName = \"skip-event-foobar\";\n\t\tList<Message<byte[]>> result = testListenerSkip(\n\t\t\t\t\"--spring.cloud.task.batch.events.skipEventBindingName=\" + bindingName, bindingName, 3);\n\t\tint readSkipCount = 0;\n\t\tint writeSkipCount = 0;\n\t\tfor (int i = 0; i < 3; i++) {\n\t\t\tString exceptionMessage = new String(result.get(i).getPayload());\n\t\t\tif (exceptionMessage.equals(SKIPPING_READ_MESSAGE)) {\n\t\t\t\treadSkipCount++;\n\t\t\t}\n\t\t\tif (exceptionMessage.equals(SKIPPING_WRITE_CONTENT)) {\n\t\t\t\twriteSkipCount++;\n\t\t\t}\n\t\t}\n\n\t\tassertThat(readSkipCount).as(\"the number of read skip events did not match\").isEqualTo(2);\n\t\tassertThat(writeSkipCount).as(\"the number of write skip events did not match\").isEqualTo(1);\n\t}\n\n\t@SpringBootApplication\n\t@EnableTask\n\t@Import(JobConfiguration.class)\n\tpublic static class BatchEventsApplication {\n\n\t}\n\n\t@SpringBootApplication\n\t@EnableTask\n\t@Import(JobSkipConfiguration.class)\n\tpublic static class BatchSkipEventsApplication {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\n\nimport org.assertj.core.api.Assertions;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.DeserializationFeature;\nimport tools.jackson.databind.ObjectMapper;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.cloud.stream.binder.test.OutputDestination;\nimport org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.messaging.Message;\n\n/**\n * @author Michael Minella\n * @author Ilayaperumal Gopinathan\n */\npublic class TaskEventTests {\n\n\tprivate static final String TASK_NAME = \"taskEventTest\";\n\n\tprivate ObjectMapper objectMapper;\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\t@BeforeEach\n\tpublic void setup() {\n\t\tobjectMapper = JsonMapper.builder().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();\n\t}\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testTaskEventListener() throws Exception {\n\t\tList<Message<byte[]>> result = testListener(\n\t\t\t\t\"--spring.cloud.task.batch.events.itemWriteEventBindingName=task-events\", \"task-events\", 2);\n\t\tTaskExecution taskExecution = this.objectMapper.readValue(result.get(0).getPayload(), TaskExecution.class);\n\t\tAssertions.assertThat(taskExecution.getTaskName())\n\t\t\t.isEqualTo(TASK_NAME)\n\t\t\t.as(String.format(\"Task name should be '%s'\", TASK_NAME));\n\t\ttaskExecution = this.objectMapper.readValue(result.get(1).getPayload(), TaskExecution.class);\n\t\tAssertions.assertThat(taskExecution.getTaskName())\n\t\t\t.isEqualTo(TASK_NAME)\n\t\t\t.as(String.format(\"Task name should be '%s'\", TASK_NAME));\n\t}\n\n\tprivate List<Message<byte[]>> testListener(String channelBinding, String bindingName, int numberToRead) {\n\t\tList<Message<byte[]>> results = new ArrayList<>();\n\t\tthis.applicationContext = new SpringApplicationBuilder()\n\t\t\t.sources(TestChannelBinderConfiguration\n\t\t\t\t.getCompleteConfiguration(BatchExecutionEventTests.BatchEventsApplication.class))\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.build()\n\t\t\t.run(getCommandLineParams(channelBinding));\n\t\tOutputDestination target = this.applicationContext.getBean(OutputDestination.class);\n\t\tfor (int i = 0; i < numberToRead; i++) {\n\t\t\tresults.add(target.receive(10000, bindingName));\n\t\t}\n\t\treturn results;\n\t}\n\n\tprivate String[] getCommandLineParams(String sinkChannelParam) {\n\t\treturn new String[] { \"--spring.cloud.task.closecontext_enable=false\", \"--spring.cloud.task.name=\" + TASK_NAME,\n\t\t\t\t\"--spring.main.web-environment=false\", \"--spring.cloud.stream.defaultBinder=rabbit\",\n\t\t\t\t\"foo=\" + UUID.randomUUID(), sinkChannelParam };\n\t}\n\n\t@EnableTask\n\t@Configuration\n\tpublic static class TaskEventsConfiguration {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/resources/application.properties",
    "content": "logging.level.org.springframework.cloud.task=DEBUG\nlogging.level.org.springframework.cloud.stream=DEBUG\nspring.application.name=batchEvents\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/resources/org/springframework/cloud/task/listener/chunk-events-sink-channel.properties",
    "content": "#\n#  Copyright 2016-2019 the original author or authors.\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#        https://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\nspring.cloud.stream.bindings.input.destination=chunk-events-foobar\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/resources/org/springframework/cloud/task/listener/item-process-sink-channel.properties",
    "content": "#\n#  Copyright 2016-2019 the original author or authors.\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#        https://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\nspring.cloud.stream.bindings.input.destination=item-process-foobar\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/resources/org/springframework/cloud/task/listener/item-read-events-sink-channel.properties",
    "content": "#\n#  Copyright 2016-2019 the original author or authors.\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#        https://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\nspring.cloud.stream.bindings.input.destination=item-read-events-foobar\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/resources/org/springframework/cloud/task/listener/item-write-events-sink-channel.properties",
    "content": "#\n#  Copyright 2016-2019 the original author or authors.\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#        https://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\nspring.cloud.stream.bindings.input.destination=item-write-events-foobar\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/resources/org/springframework/cloud/task/listener/job-execution-sink-channel.properties",
    "content": "#\n#  Copyright 2016-2019 the original author or authors.\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#        https://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\nspring.cloud.stream.bindings.input.destination=foobar\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/resources/org/springframework/cloud/task/listener/sink-channel.properties",
    "content": "#\n#  Copyright 2016-2019 the original author or authors.\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#        https://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\nspring.cloud.stream.bindings.input.destination=test\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/resources/org/springframework/cloud/task/listener/skip-events-sink-channel.properties",
    "content": "#\n#  Copyright 2016-2019 the original author or authors.\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#        https://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\nspring.cloud.stream.bindings.input.destination=skip-event-foobar\n"
  },
  {
    "path": "spring-cloud-task-integration-tests/src/test/resources/org/springframework/cloud/task/listener/step-execution-sink-channel.properties",
    "content": "#\n#  Copyright 2016-2019 the original author or authors.\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#        https://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\nspring.cloud.stream.bindings.input.destination=step-execution-foobar\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/.mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/README.adoc",
    "content": "= Task Events\n\nThis is a task application that emits batch job events to the following channels:\n\n\t* job-execution-events\n\t* step-execution-events\n\t* chunk-events\n\t* item-read-events\n\t* item-process-events\n\t* item-write-events\n\t* skip-events\n\nNote: More information on this topic is available https://docs.spring.io/spring-cloud-task/docs/current/reference/html/#stream-integration-batch-events[here].\n\n== Requirements:\n\n* Java 17 or Above\n\n== Build:\n\n[source,shell]\n----\n./mvnw clean install\n----\n\n== Execution:\n\n[source,shell]\n----\njava -jar target/batch-events-5.0.0.jar\n----\n\nFor example, you can listen for specific job-execution events on a specified channel with a Spring Cloud Stream Sink\nlike the https://github.com/spring-cloud/stream-applications/tree/main/applications/sink/log-sink[log sink] using the following:\n\n[source,shell]\n----\n$ java -jar <PATH_TO_LOG_SINK_JAR>/log-sink-rabbit-3.1.2.jar --server.port=9090\n--spring.cloud.stream.bindings.input.destination=job-execution-events\n----\n\n== Dependencies:\n\nThe batch-events sample requires an instance of RabbitMQ to be running.\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/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#    https://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# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n           #\n           # Look for the Apple JDKs first to preserve the existing behaviour, and then look\n           # for the new JDKs provided by Oracle.\n           #\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L \"/Library/Java/JavaVirtualMachines/CurrentJDK\" ] ; then\n             #\n             # Oracle JDKs\n             #\n             export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -x \"/usr/libexec/java_home\" ]; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=`/usr/libexec/java_home`\n           fi\n           ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Migwn, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\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    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\nfi\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n  local basedir=$(pwd)\n  local wdir=$(pwd)\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    wdir=$(cd \"$wdir/..\"; pwd)\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} \"$@\"\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/mvnw.cmd",
    "content": "@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    https://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 Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\nset MAVEN_CMD_LINE_ARGS=%*\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\n\nset WRAPPER_JAR=\"\".\\.mvn\\wrapper\\maven-wrapper.jar\"\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.spring.cloud</groupId>\n\t<artifactId>batch-events</artifactId>\n\t<version>5.0.0-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<name>Batch Events Sample Application</name>\n\t<description>Sample of sending batch events via Spring Cloud Streams</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>4.0.2</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>17</java.version>\n\t\t<spring-cloud-stream.version>5.0.2-SNAPSHOT</spring-cloud-stream.version>\n\t\t<spring-cloud-task.version>5.0.2-SNAPSHOT</spring-cloud-task.version>\n\t</properties>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-stream-dependencies</artifactId>\n\t\t\t\t<version>${spring-cloud-stream.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${spring-cloud-task.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-batch</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-stream-rabbit</artifactId>\n\t\t\t<scope>compile</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-stream-binder-rabbit-test-support</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-task</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-stream-test-binder</artifactId>\n\t\t\t<version>${spring-cloud-stream.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<!--skip deploy (this is just a test module) -->\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>withoutDockerTests</id>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludedGroups>DockerRequired</excludedGroups>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/src/main/java/io/spring/cloud/BatchEventsApplication.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.cloud;\n\nimport java.util.Arrays;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.scope.context.ChunkContext;\nimport org.springframework.batch.core.step.Step;\nimport org.springframework.batch.core.step.StepContribution;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.core.step.tasklet.Tasklet;\nimport org.springframework.batch.infrastructure.item.Chunk;\nimport org.springframework.batch.infrastructure.item.ItemProcessor;\nimport org.springframework.batch.infrastructure.item.ItemWriter;\nimport org.springframework.batch.infrastructure.item.support.ListItemReader;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n@EnableTask\n@SpringBootApplication\npublic class BatchEventsApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(BatchEventsApplication.class, args);\n\t}\n\n\t@Configuration\n\tpublic static class JobConfiguration {\n\n\t\tprivate static final int DEFAULT_CHUNK_COUNT = 3;\n\n\t\t@Autowired\n\t\tprivate JobRepository jobRepository;\n\n\t\t@Autowired\n\t\tprivate PlatformTransactionManager transactionManager;\n\n\t\t@Bean\n\t\tpublic Step step1() {\n\t\t\treturn new StepBuilder(\"step1\", this.jobRepository).tasklet(new Tasklet() {\n\t\t\t\t@Override\n\t\t\t\tpublic RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {\n\t\t\t\t\tSystem.out.println(\"Tasklet has run\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}\n\t\t\t}, transactionManager).build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic Step step2() {\n\t\t\treturn new StepBuilder(\"step2\", this.jobRepository)\n\t\t\t\t.<String, String>chunk(DEFAULT_CHUNK_COUNT, this.transactionManager)\n\t\t\t\t.reader(new ListItemReader<>(Arrays.asList(\"1\", \"2\", \"3\", \"4\", \"5\", \"6\")))\n\t\t\t\t.processor(new ItemProcessor<String, String>() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic String process(String item) throws Exception {\n\t\t\t\t\t\treturn String.valueOf(Integer.parseInt(item) * -1);\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.writer(new ItemWriter<String>() {\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic void write(Chunk<? extends String> items) throws Exception {\n\t\t\t\t\t\tfor (String item : items) {\n\t\t\t\t\t\t\tSystem.out.println(\">> \" + item);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.build();\n\t\t}\n\n\t\t@Bean\n\t\tpublic Job job() {\n\t\t\treturn new JobBuilder(\"job\", this.jobRepository).start(step1()).next(step2()).build();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/src/main/java/io/spring/cloud/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Batch events sample application for Spring Cloud Task.\n */\npackage io.spring.cloud;"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/src/main/resources/application.properties",
    "content": "logging.level.org.springframework.cloud.task=DEBUG\nlogging.level.org.springframework.cloud.stream=DEBUG\nspring.application.name=batchEvents\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/src/main/resources/logback-test.xml",
    "content": "<configuration>\n\t<include resource=\"org/springframework/boot/logging/logback/base.xml\"/>\n\t<logger name=\"org.apache.http\" level=\"WARN\"/>\n\t<logger name=\"com.github.dockerjava\" level=\"WARN\"/>\n\t<logger name=\"org.zeroturnaround.exec\" level=\"WARN\"/>\n</configuration>\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/src/test/java/io/spring/cloud/BatchEventsApplicationTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.cloud;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.Tag;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.DeserializationFeature;\nimport tools.jackson.databind.ObjectMapper;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.cloud.stream.binder.test.OutputDestination;\nimport org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;\nimport org.springframework.cloud.task.batch.listener.support.JobExecutionEvent;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.context.annotation.Import;\nimport org.springframework.messaging.Message;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n@Tag(\"DockerRequired\")\npublic class BatchEventsApplicationTests {\n\n\tprivate static final String TASK_NAME = \"taskEventTest\";\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\tprivate ObjectMapper objectMapper;\n\n\tprivate final TaskEventProperties taskEventProperties = new TaskEventProperties();\n\n\t@BeforeEach\n\tpublic void setup() {\n\t\tobjectMapper = JsonMapper.builder().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();\n\t}\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testExecution() throws Exception {\n\t\tList<Message<byte[]>> result = testListener(taskEventProperties.getJobExecutionEventBindingName(), 1);\n\t\tJobExecutionEvent jobExecutionEvent = this.objectMapper.readValue(result.get(0).getPayload(),\n\t\t\t\tJobExecutionEvent.class);\n\t\tassertThat(jobExecutionEvent.getJobInstance().getJobName()).isEqualTo(\"job\").as(\"Job name should be job\");\n\t}\n\n\tprivate String[] getCommandLineParams(boolean enableFailJobConfig) {\n\t\tString jobConfig = enableFailJobConfig ? \"--spring.cloud.task.test.enable-job-configuration=true\"\n\t\t\t\t: \"--spring.cloud.task.test.enable-fail-job-configuration=true\";\n\t\treturn new String[] { \"--spring.cloud.task.closecontext_enable=false\", \"--spring.cloud.task.name=\" + TASK_NAME,\n\t\t\t\t\"--spring.main.web-environment=false\", \"--spring.cloud.stream.defaultBinder=rabbit\",\n\t\t\t\t\"--spring.cloud.stream.bindings.task-events.destination=test\", jobConfig, \"foo=\" + UUID.randomUUID() };\n\t}\n\n\tprivate List<Message<byte[]>> testListener(String bindingName, int numberToRead) {\n\t\tList<Message<byte[]>> results = new ArrayList<>();\n\t\tthis.applicationContext = new SpringApplicationBuilder()\n\t\t\t.sources(TestChannelBinderConfiguration.getCompleteConfiguration(BatchEventsTestApplication.class))\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.build()\n\t\t\t.run(getCommandLineParams(true));\n\t\tOutputDestination target = this.applicationContext.getBean(OutputDestination.class);\n\t\tfor (int i = 0; i < numberToRead; i++) {\n\t\t\tresults.add(target.receive(10000, bindingName));\n\t\t}\n\t\treturn results;\n\t}\n\n\t@SpringBootApplication\n\t@Import({ BatchEventsApplication.class })\n\tpublic static class BatchEventsTestApplication {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-events/src/test/resources/io/spring/task/listener/job-listener-sink-channel.properties",
    "content": "#\n#  Copyright 2015-2019 the original author or authors.\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#        https://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\nspring.cloud.stream.bindings.input.destination=job-execution-events\nspring.cloud.stream.bindings.input.group=testgroup\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/.mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/README.adoc",
    "content": "= Spring Batch Job Task\n\nThis is a Spring Cloud Task application that executes a single Spring Batch Job.\n\n== Requirements:\n\n* Java 17 or Above\n\n== Classes:\n\n* BatchJobApplication - the Spring Boot Main Application\n* JobConfiguration - the configuration for the Spring Batch jobs\n\n== Build:\n\n[source,shell]\n----\nmvn clean package\n----\n\n== Run:\n\n[source,shell]\n----\njava -jar target/batch-job-5.0.0.jar\n----\n\n== Native Build:\n\n[source,shell]\n----\nmvn -Pnative native:compile\n----\n\n== Native Run:\n\n[source,shell]\n----\n./target/batch-job\n----\n\n== Run the application with a Postgesql test container\n[source,shell]\n----\n./mvnw spring-boot:test-run\n----\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/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#    https://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# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n           #\n           # Look for the Apple JDKs first to preserve the existing behaviour, and then look\n           # for the new JDKs provided by Oracle.\n           #\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L \"/Library/Java/JavaVirtualMachines/CurrentJDK\" ] ; then\n             #\n             # Oracle JDKs\n             #\n             export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -x \"/usr/libexec/java_home\" ]; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=`/usr/libexec/java_home`\n           fi\n           ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Migwn, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\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    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\nfi\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n  local basedir=$(pwd)\n  local wdir=$(pwd)\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    wdir=$(cd \"$wdir/..\"; pwd)\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} \"$@\"\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/mvnw.cmd",
    "content": "@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    https://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 Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\nset MAVEN_CMD_LINE_ARGS=%*\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\n\nset WRAPPER_JAR=\"\".\\.mvn\\wrapper\\maven-wrapper.jar\"\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.spring.cloud</groupId>\n\t<artifactId>batch-job</artifactId>\n\t<packaging>jar</packaging>\n\t<version>5.0.0-SNAPSHOT</version>\n\t<description>Spring Cloud Task Batch Example</description>\n\n\t<name>Batch Job Sample Application</name>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>4.0.2</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>17</java.version>\n\t</properties>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-batch</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-task</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t\t<scope>runtime</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mariadb.jdbc</groupId>\n\t\t\t<artifactId>mariadb-java-client</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.testcontainers</groupId>\n\t\t\t<artifactId>testcontainers-postgresql</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-testcontainers</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.postgresql</groupId>\n\t\t\t<artifactId>postgresql</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<!--skip deploy (this is just a test module) -->\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/src/main/java/io/spring/BatchJobApplication.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.task.configuration.EnableTask;\n\n@EnableTask\n@SpringBootApplication\npublic class BatchJobApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(BatchJobApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/src/main/java/io/spring/configuration/JobConfiguration.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.configuration;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.job.builder.JobBuilder;\nimport org.springframework.batch.core.repository.JobRepository;\nimport org.springframework.batch.core.scope.context.ChunkContext;\nimport org.springframework.batch.core.step.StepContribution;\nimport org.springframework.batch.core.step.builder.StepBuilder;\nimport org.springframework.batch.core.step.tasklet.Tasklet;\nimport org.springframework.batch.infrastructure.repeat.RepeatStatus;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.transaction.PlatformTransactionManager;\n\n/**\n * @author Michael Minella\n */\n@Configuration(proxyBeanMethods = false)\npublic class JobConfiguration {\n\n\tprivate static final Log logger = LogFactory.getLog(JobConfiguration.class);\n\n\t@Autowired\n\tpublic JobRepository jobRepository;\n\n\t@Autowired\n\tpublic PlatformTransactionManager transactionManager;\n\n\t@Bean\n\tpublic Job job1() {\n\t\treturn new JobBuilder(\"job1\", this.jobRepository)\n\t\t\t.start(new StepBuilder(\"job1step1\", this.jobRepository).tasklet(new Tasklet() {\n\t\t\t\t@Override\n\t\t\t\tpublic RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {\n\t\t\t\t\tlogger.info(\"Job1 was run\");\n\t\t\t\t\treturn RepeatStatus.FINISHED;\n\t\t\t\t}\n\t\t\t}, transactionManager).build())\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/src/main/java/io/spring/configuration/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Configuration classes for the batch job sample application.\n */\npackage io.spring.configuration;"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/src/main/java/io/spring/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Batch job sample application for Spring Cloud Task.\n */\npackage io.spring;"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/src/main/resources/application.properties",
    "content": "spring.application.name=Demo Batch Job Task\nlogging.level.org.springframework.cloud.task=DEBUG\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/src/test/java/io/spring/BatchJobApplicationTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Verifies that the Task Application outputs the correct task log entries.\n *\n * @author Michael Minella\n */\n@ExtendWith(OutputCaptureExtension.class)\npublic class BatchJobApplicationTests {\n\n\t@Test\n\tpublic void testBatchJobApp(CapturedOutput capturedOutput) throws Exception {\n\t\tfinal String JOB_RUN_MESSAGE = \" was run\";\n\t\tfinal String CREATE_TASK_MESSAGE = \"Creating: TaskExecution{executionId=\";\n\t\tfinal String UPDATE_TASK_MESSAGE = \"Updating: TaskExecution with executionId=\";\n\t\tfinal String JOB_ASSOCIATION_MESSAGE = \"The job execution id \";\n\t\tfinal String EXIT_CODE_MESSAGE = \"with the following {exitCode=0\";\n\n\t\tSpringApplication.run(BatchJobApplication.class);\n\n\t\tString output = capturedOutput.toString();\n\t\tassertThat(output).contains(JOB_RUN_MESSAGE);\n\t\tassertThat(output).contains(CREATE_TASK_MESSAGE);\n\t\tassertThat(output).contains(UPDATE_TASK_MESSAGE);\n\t\tassertThat(output).contains(EXIT_CODE_MESSAGE);\n\n\t\tint i = output.indexOf(JOB_ASSOCIATION_MESSAGE);\n\n\t\tassertThat(i).isGreaterThan(0);\n\n\t\tString taskTitle = \"taskName='Demo Batch Job Task'\";\n\t\tPattern pattern = Pattern.compile(taskTitle);\n\t\tMatcher matcher = pattern.matcher(output);\n\n\t\tint count = 0;\n\t\twhile (matcher.find()) {\n\t\t\tcount++;\n\t\t}\n\t\tassertThat(count).isEqualTo(1);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/src/test/java/io/spring/BatchJobTestConfiguration.java",
    "content": "/*\n * Copyright 2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport org.testcontainers.postgresql.PostgreSQLContainer;\nimport org.testcontainers.utility.DockerImageName;\n\nimport org.springframework.boot.test.context.TestConfiguration;\nimport org.springframework.boot.testcontainers.service.connection.ServiceConnection;\nimport org.springframework.context.annotation.Bean;\n\n@TestConfiguration(proxyBeanMethods = false)\nclass BatchJobTestConfiguration {\n\n\t@Bean\n\t@ServiceConnection\n\tpublic PostgreSQLContainer postgresSQLContainer() {\n\t\treturn new PostgreSQLContainer(DockerImageName.parse(\"postgres:15.1\"));\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/src/test/java/io/spring/TestBatchJobApp.java",
    "content": "/*\n * Copyright 2023 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport org.springframework.boot.SpringApplication;\n\npublic class TestBatchJobApp {\n\n\tpublic static void main(String[] args) {\n\t\tString[] myArgs = { \"--spring.batch.jdbc.initialize-schema=always\" };\n\t\tSpringApplication.from(BatchJobApplication::main).with(BatchJobTestConfiguration.class).run(myArgs);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/batch-job/src/test/resources/application.properties",
    "content": "#\n# Copyright 2016-2019 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nlogging.level.root=DEBUG\nspring.application.name=Demo Batch Job Task\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/.mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/README.adoc",
    "content": "= JPA Sample Task\n\nThis is a Spring Cloud Task Boot Application that uses JPA to persist data to\na data store.\n\n== Requirements:\n\n* Java 17 or Above\n\n== Classes:\n\n* JpaApplication - the Spring Boot Main Application.\n* TaskRunComponent - Component responsible for writing data to the repository.\n* TaskRunOutput - Entity to be written to the repository.\n\n== Build:\n\n[source,shell]\n----\nmvn clean package\n----\n\n== Run:\n\n[source,shell]\n----\njava -jar target/jpa-sample-5.0.0.jar\n----\n\n== Native Build:\n\n[source,shell]\n----\nmvn -Pnative native:compile\n----\n\n== Native Run:\n\n[source,shell]\n----\n./target/jpa-sample\n----\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/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#    https://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# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n           #\n           # Look for the Apple JDKs first to preserve the existing behaviour, and then look\n           # for the new JDKs provided by Oracle.\n           #\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L \"/Library/Java/JavaVirtualMachines/CurrentJDK\" ] ; then\n             #\n             # Oracle JDKs\n             #\n             export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -x \"/usr/libexec/java_home\" ]; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=`/usr/libexec/java_home`\n           fi\n           ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Migwn, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\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    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\nfi\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n  local basedir=$(pwd)\n  local wdir=$(pwd)\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    wdir=$(cd \"$wdir/..\"; pwd)\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} \"$@\"\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/mvnw.cmd",
    "content": "@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    https://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 Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\nset MAVEN_CMD_LINE_ARGS=%*\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\n\nset WRAPPER_JAR=\"\".\\.mvn\\wrapper\\maven-wrapper.jar\"\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.spring.cloud</groupId>\n\t<artifactId>jpa-sample</artifactId>\n\t<packaging>jar</packaging>\n\t<version>5.0.0-SNAPSHOT</version>\n\t<description>To show users how to enable a task with a JPA application.</description>\n\n\t<name>Spring Cloud Task JPA Sample Application</name>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>4.0.2</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<properties>\n\t\t<spring-cloud-commons.version>5.0.2-SNAPSHOT</spring-cloud-commons.version>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>17</java.version>\n\t</properties>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-task</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-data-jpa</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-test-support</artifactId>\n\t\t\t<version>${spring-cloud-commons.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<!--skip deploy (this is just a test module) -->\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/JpaApplication.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.task.configuration.EnableTask;\n\n@EnableTask\n@SpringBootApplication\npublic class JpaApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(JpaApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/configuration/TaskRunComponent.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.configuration;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.cloud.task.listener.annotation.BeforeTask;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.stereotype.Component;\n\n/**\n * Records an entry in the TASK_RUN_OUTPUT table on the BeforeTask event.\n *\n * @author Glenn Renfro\n * @author Pas Apicella\n */\n@Component\npublic class TaskRunComponent {\n\n\tprivate static final Log logger = LogFactory.getLog(TaskRunComponent.class);\n\n\t@Autowired\n\tprivate TaskRunRepository taskRunRepository;\n\n\t@BeforeTask\n\tpublic void init(TaskExecution taskExecution) {\n\t\tString execDate = new SimpleDateFormat().format(new Date());\n\t\tthis.taskRunRepository.save(new TaskRunOutput(\"Executed at \" + execDate));\n\t\tlogger.info(\"Executed at : \" + execDate);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/configuration/TaskRunOutput.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.configuration;\n\nimport jakarta.persistence.Entity;\nimport jakarta.persistence.GeneratedValue;\nimport jakarta.persistence.GenerationType;\nimport jakarta.persistence.Id;\nimport jakarta.persistence.Table;\n\n/**\n * Entity for the id and output to be written to the data store.\n *\n * @author Pas Apicella\n * @author Glenn Renfro\n */\n@Entity\n@Table(name = \"TASK_RUN_OUTPUT\")\npublic class TaskRunOutput {\n\n\t@Id\n\t@GeneratedValue(strategy = GenerationType.AUTO)\n\tprivate Long id;\n\n\tprivate String output;\n\n\tpublic TaskRunOutput() {\n\t}\n\n\tpublic TaskRunOutput(String output) {\n\t\tthis.output = output;\n\t}\n\n\tpublic Long getId() {\n\t\treturn this.id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic String getOutput() {\n\t\treturn this.output;\n\t}\n\n\tpublic void setOutput(String output) {\n\t\tthis.output = output;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"TaskRunOutput{\" + \"id=\" + this.id + \", output='\" + this.output + '\\'' + '}';\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/configuration/TaskRunRepository.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.configuration;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\n\n/**\n * @author Pas Apicella\n * @author Glenn Renfro\n */\npublic interface TaskRunRepository extends JpaRepository<TaskRunOutput, Long> {\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/configuration/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Configuration classes for the JPA sample application.\n */\npackage io.spring.configuration;"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * JPA sample application for Spring Cloud Task.\n */\npackage io.spring;"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/src/main/resources/application-cloud.yml",
    "content": "spring:\n  jpa:\n    hibernate:\n      ddl-auto: update\n    show-sql: true\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/src/main/resources/application.yml",
    "content": "spring:\n  jpa:\n    hibernate:\n      ddl-auto: update\n    show-sql: true\n  application:\n    name: Spring Cloud Task JPA Sample Application\nlogging:\n  level:\n    org:\n      springframework:\n        cloud:\n          task: debug\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/src/test/java/io/spring/JpaApplicationTests.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport java.sql.SQLException;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.h2.tools.Server;\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;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.DriverManagerDataSource;\nimport org.springframework.test.util.TestSocketUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Verifies that a JPA Application can write its data to a repository.\n *\n * @author Glenn Renfro\n */\n@ExtendWith(OutputCaptureExtension.class)\npublic class JpaApplicationTests {\n\n\tprivate final static String DATASOURCE_URL;\n\n\tprivate final static String DATASOURCE_USER_NAME = \"SA\";\n\n\tprivate final static String DATASOURCE_USER_PASSWORD = \"\";\n\n\tprivate final static String DATASOURCE_DRIVER_CLASS_NAME = \"org.h2.Driver\";\n\n\tprivate static int randomPort;\n\n\tstatic {\n\t\trandomPort = TestSocketUtils.findAvailableTcpPort();\n\t\tDATASOURCE_URL = \"jdbc:h2:tcp://localhost:\" + randomPort + \"/mem:dataflow;DB_CLOSE_DELAY=-1;\"\n\t\t\t\t+ \"DB_CLOSE_ON_EXIT=FALSE\";\n\t}\n\n\tprivate ConfigurableApplicationContext context;\n\n\tprivate DataSource dataSource;\n\n\tprivate Server server;\n\n\t@BeforeEach\n\tpublic void setup() {\n\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\tdataSource.setDriverClassName(DATASOURCE_DRIVER_CLASS_NAME);\n\t\tdataSource.setUrl(DATASOURCE_URL);\n\t\tdataSource.setUsername(DATASOURCE_USER_NAME);\n\t\tdataSource.setPassword(DATASOURCE_USER_PASSWORD);\n\t\tthis.dataSource = dataSource;\n\t\ttry {\n\t\t\tthis.server = Server\n\t\t\t\t.createTcpServer(\"-tcp\", \"-ifNotExists\", \"-tcpAllowOthers\", \"-tcpPort\", String.valueOf(randomPort))\n\t\t\t\t.start();\n\t\t}\n\t\tcatch (SQLException e) {\n\t\t\tthrow new IllegalStateException(e);\n\t\t}\n\t}\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.context != null && this.context.isActive()) {\n\t\t\tthis.context.close();\n\t\t}\n\t\tthis.server.stop();\n\t}\n\n\t@Test\n\tpublic void testBatchJobApp(CapturedOutput capturedOutput) {\n\t\tfinal String INSERT_MESSAGE = \"Hibernate: insert into task_run_output (\";\n\t\tthis.context = SpringApplication.run(JpaApplication.class, \"--spring.datasource.url=\" + DATASOURCE_URL,\n\t\t\t\t\"--spring.datasource.username=\" + DATASOURCE_USER_NAME,\n\t\t\t\t\"--spring.datasource.driverClassName=\" + DATASOURCE_DRIVER_CLASS_NAME,\n\t\t\t\t\"--spring.jpa.database-platform=org.hibernate.dialect.H2Dialect\");\n\t\tString output = capturedOutput.toString();\n\t\tassertThat(output.contains(INSERT_MESSAGE)).as(\"Unable to find the insert message: \" + output).isTrue();\n\t\tJdbcTemplate template = new JdbcTemplate(this.dataSource);\n\t\tMap<String, Object> result = template.queryForMap(\"Select * from TASK_RUN_OUTPUT\");\n\t\tassertThat(result.get(\"ID\")).isEqualTo(1L);\n\t\tassertThat(((String) result.get(\"OUTPUT\"))).contains(\"Executed at\");\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/jpa-sample/src/test/resources/application.properties",
    "content": "#\n# Copyright 2018-2019 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nlogging.level.root=DEBUG\nspring.application.name=Spring Cloud Task JPA Sample Application\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/.mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/README.adoc",
    "content": "= Multiple DataSources Sample Task\n\nThis is a Spring Boot application that utilizes two DataSources and explicitly configures\nwhich one to be used for the Spring Cloud Task repository.\n\n== Requirements:\n\n* Java 17 or Above\n\n== Classes:\n\n* `MultipleDataSourcesApplication` - the Spring Boot Main Application.\n* `SampleCommandLineRunner` - the `CommandLineRunner` implementation for this task.  It outputs the number of `DataSource` beans found in the context (should be 2).\n* `EmbeddedDataSourceConfiguration` - Configures two `DataSource` beans using embedded databases.\n* `ExternalDataSourceConfiguration` - Configures two `DataSource` beans using external databases.\n\n* `CustomTaskConfigurer` - Uses a Spring `@Qualifier` to specify the correct `DataSource` to use.\n\n== Build:\n\n[source,shell]\n----\nmvn clean package\n----\n\n== Execute sample using 2 embedded databases (default):\n\n[source,shell]\n----\njava -jar target/multiple-datasources-5.0.0.jar\n----\n\n== Native Build:\n\n[source,shell]\n----\nmvn -Pnative native:compile\n----\n\n== RUn sample using 2 embedded databases (default) with native app:\n\n[source,shell]\n----\n./target/multiple-datasources\n----\n\n== Execute sample using 2 external databases:\n\nUsing the `external` profile, users will be able to establish both the default `spring.datasource` data source and a `second.datasource` data source.\nFor example:\n[source,shell,indent=2]\n----\nexport spring_datasource_url=<your db url>\nexport spring_datasource_username=<your db user name>\nexport spring_datasource_password=<your db user password>\nexport spring_datasource_driverClassName=org.mariadb.jdbc.Driver\nexport second_datasource_url=jdbc:<your db url>\nexport second_datasource_username=<your db user name>\nexport second_datasource_password=<your db user password>\nexport second_datasource_driverClassName=org.mariadb.jdbc.Driver\njava -jar target/multiple-datasources-2.3.0-RELEASE.jar --spring.profiles.active=external\n----\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/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#    https://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# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n           #\n           # Look for the Apple JDKs first to preserve the existing behaviour, and then look\n           # for the new JDKs provided by Oracle.\n           #\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L \"/Library/Java/JavaVirtualMachines/CurrentJDK\" ] ; then\n             #\n             # Oracle JDKs\n             #\n             export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -x \"/usr/libexec/java_home\" ]; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=`/usr/libexec/java_home`\n           fi\n           ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Migwn, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\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    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\nfi\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n  local basedir=$(pwd)\n  local wdir=$(pwd)\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    wdir=$(cd \"$wdir/..\"; pwd)\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} \"$@\"\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/mvnw.cmd",
    "content": "@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    https://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 Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\nset MAVEN_CMD_LINE_ARGS=%*\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\n\nset WRAPPER_JAR=\"\".\\.mvn\\wrapper\\maven-wrapper.jar\"\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.spring.cloud</groupId>\n\t<artifactId>multiple-datasources</artifactId>\n\t<packaging>jar</packaging>\n\t<version>5.0.1-SNAPSHOT</version>\n\t<description>To show users how to enable a task with a multiple DataSources.\n\t</description>\n\n\t<name>Spring Cloud Task Multiple DataSources Application</name>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>4.0.2</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<properties>\n\t\t<spring-cloud-commons.version>5.0.2-SNAPSHOT</spring-cloud-commons.version>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>17</java.version>\n\t</properties>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-task</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mariadb.jdbc</groupId>\n\t\t\t<artifactId>mariadb-java-client</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-test-support</artifactId>\n\t\t\t<version>${spring-cloud-commons.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<!--skip deploy (this is just a test module) -->\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n\n</project>\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/MultipleDataSourcesApplication.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.task.configuration.EnableTask;\n\n/**\n * @author Michael Minella\n */\n@EnableTask\n@SpringBootApplication\npublic class MultipleDataSourcesApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(MultipleDataSourcesApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/configuration/CustomTaskConfigurer.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.configuration;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.cloud.task.configuration.DefaultTaskConfigurer;\nimport org.springframework.stereotype.Component;\n\n/**\n * @author Michael Minella\n */\n@Component\npublic class CustomTaskConfigurer extends DefaultTaskConfigurer {\n\n\t@Autowired\n\tpublic CustomTaskConfigurer(@Qualifier(\"secondDataSource\") DataSource dataSource) {\n\t\tsuper(dataSource);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/configuration/EmbeddedDataSourceConfiguration.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.configuration;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\n/**\n * Creates two data sources that use embedded databases.\n *\n * @author Michael Minella\n * @author Glenn Renfro\n */\n@Configuration(proxyBeanMethods = false)\n@Profile(\"embedded\")\npublic class EmbeddedDataSourceConfiguration {\n\n\t@Bean\n\tpublic DataSource dataSource() {\n\t\treturn new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();\n\t}\n\n\t@Bean\n\tpublic DataSource secondDataSource() {\n\t\treturn new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/configuration/ExternalDataSourceConfiguration.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.configuration;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.boot.jdbc.autoconfigure.DataSourceProperties;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\n\n/**\n * Creates two data sources that use external databases.\n *\n * @author Glenn Renfro\n */\n@Configuration(proxyBeanMethods = false)\n@Profile(\"external\")\npublic class ExternalDataSourceConfiguration {\n\n\t@Bean(name = \"springDataSourceProperties\")\n\t@ConfigurationProperties(\"spring.datasource\")\n\t@Primary\n\tpublic DataSourceProperties springDataSourceProperties() {\n\t\treturn new DataSourceProperties();\n\t}\n\n\t@Bean(name = \"secondDataSourceProperties\")\n\t@ConfigurationProperties(\"second.datasource\")\n\tpublic DataSourceProperties myDataSourceProperties() {\n\t\treturn new DataSourceProperties();\n\t}\n\n\t@Bean(name = \"springDataSource\")\n\t@Primary\n\tpublic DataSource dataSource(\n\t\t\t@Qualifier(\"springDataSourceProperties\") DataSourceProperties springDataSourceProperties) {\n\t\treturn DataSourceBuilder.create()\n\t\t\t.driverClassName(springDataSourceProperties.getDriverClassName())\n\t\t\t.url(springDataSourceProperties.getUrl())\n\t\t\t.password(springDataSourceProperties.getPassword())\n\t\t\t.username(springDataSourceProperties.getUsername())\n\t\t\t.build();\n\t}\n\n\t@Bean\n\tpublic DataSource secondDataSource(\n\t\t\t@Qualifier(\"secondDataSourceProperties\") DataSourceProperties secondDataSourceProperties) {\n\t\treturn DataSourceBuilder.create()\n\t\t\t.driverClassName(secondDataSourceProperties.getDriverClassName())\n\t\t\t.url(secondDataSourceProperties.getUrl())\n\t\t\t.password(secondDataSourceProperties.getPassword())\n\t\t\t.username(secondDataSourceProperties.getUsername())\n\t\t\t.build();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/configuration/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Configuration classes for the multiple datasources sample application.\n */\npackage io.spring.configuration;"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Multiple datasources sample application for Spring Cloud Task.\n */\npackage io.spring;"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/task/SampleCommandLineRunner.java",
    "content": "/*\n * Copyright 2018-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.task;\n\nimport java.util.List;\n\nimport javax.sql.DataSource;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.stereotype.Component;\n\n/**\n * @author Michael Minella\n */\n@Component\npublic class SampleCommandLineRunner implements CommandLineRunner {\n\n\tprivate List<DataSource> dataSources;\n\n\t@Autowired\n\tpublic SampleCommandLineRunner(List<DataSource> dataSources) {\n\t\tthis.dataSources = dataSources;\n\t}\n\n\t@Override\n\tpublic void run(String... args) throws Exception {\n\t\tSystem.out.println(\"There are \" + this.dataSources.size() + \" DataSources within this application\");\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/task/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Task implementation classes for the multiple datasources sample application.\n */\npackage io.spring.task;"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/main/resources/application.properties",
    "content": "spring.application.name=Demo Multiple DataSources Task\nlogging.level.org.springframework.cloud.task=DEBUG\n\nspring.profiles.active=embedded\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/test/java/io/spring/MultiDataSourcesApplicationTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Michael Minella\n */\n@ExtendWith(OutputCaptureExtension.class)\npublic class MultiDataSourcesApplicationTests {\n\n\t@Test\n\tpublic void testTimeStampApp(CapturedOutput capturedOutput) throws Exception {\n\n\t\tSpringApplication.run(MultipleDataSourcesApplication.class, \"--spring.profiles.active=embedded\");\n\n\t\tString output = capturedOutput.toString();\n\n\t\tassertThat(output.contains(\"There are 2 DataSources within this application\"))\n\t\t\t.as(\"Unable to find CommandLineRunner output: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(\"Creating: TaskExecution{\")).as(\"Unable to find start task message: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(\"Updating: TaskExecution\")).as(\"Unable to find update task message: \" + output)\n\t\t\t.isTrue();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/test/java/io/spring/MultiDataSourcesExternalApplicationTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport java.sql.SQLException;\n\nimport org.h2.tools.Server;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\nimport org.springframework.test.util.TestSocketUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n */\n@ExtendWith({ OutputCaptureExtension.class, SpringExtension.class })\n@SpringBootTest(classes = { MultiDataSourcesExternalApplicationTests.TaskLauncherConfiguration.class })\npublic class MultiDataSourcesExternalApplicationTests {\n\n\tprivate final static String DATASOURCE_URL;\n\n\tprivate final static String SECOND_DATASOURCE_URL;\n\n\tprivate final static String DATASOURCE_USER_NAME = \"SA\";\n\n\tprivate final static String DATASOURCE_USER_PASSWORD = \"''\";\n\n\tprivate final static String DATASOURCE_DRIVER_CLASS_NAME = \"org.h2.Driver\";\n\n\tprivate static int randomPort;\n\n\tprivate static int secondRandomPort;\n\n\tstatic {\n\t\trandomPort = TestSocketUtils.findAvailableTcpPort();\n\t\tDATASOURCE_URL = \"jdbc:h2:tcp://localhost:\" + randomPort + \"/mem:dataflow;DB_CLOSE_DELAY=-1;\"\n\t\t\t\t+ \"DB_CLOSE_ON_EXIT=FALSE\";\n\t\tsecondRandomPort = TestSocketUtils.findAvailableTcpPort();\n\t\tSECOND_DATASOURCE_URL = \"jdbc:h2:tcp://localhost:\" + randomPort + \"/mem:dataflow;DB_CLOSE_DELAY=-1;\"\n\t\t\t\t+ \"DB_CLOSE_ON_EXIT=FALSE\";\n\t}\n\n\t@Test\n\tpublic void testTimeStampApp(CapturedOutput capturedOutput) throws Exception {\n\n\t\tSpringApplication.run(MultipleDataSourcesApplication.class, \"--spring.profiles.active=external\",\n\t\t\t\t\"--spring.datasource.url=\" + DATASOURCE_URL, \"--spring.datasource.username=\" + DATASOURCE_USER_NAME,\n\t\t\t\t\"--spring.datasource.password=\" + DATASOURCE_USER_PASSWORD,\n\t\t\t\t\"--spring.datasource.driverClassName=\" + DATASOURCE_DRIVER_CLASS_NAME,\n\t\t\t\t\"--second.datasource.url=\" + SECOND_DATASOURCE_URL,\n\t\t\t\t\"--second.datasource.username=\" + DATASOURCE_USER_NAME,\n\t\t\t\t\"--second.datasource.password=\" + DATASOURCE_USER_PASSWORD,\n\t\t\t\t\"--second.datasource.driverClassName=\" + DATASOURCE_DRIVER_CLASS_NAME);\n\n\t\tString output = capturedOutput.toString();\n\n\t\tassertThat(output.contains(\"There are 2 DataSources within this application\"))\n\t\t\t.as(\"Unable to find CommandLineRunner output: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(\"Creating: TaskExecution{\")).as(\"Unable to find start task message: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(\"Updating: TaskExecution\")).as(\"Unable to find update task message: \" + output)\n\t\t\t.isTrue();\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tpublic static class TaskLauncherConfiguration {\n\n\t\tprivate static Server defaultServer;\n\n\t\tprivate static Server secondServer;\n\n\t\t@Bean\n\t\tpublic Server initH2TCPServer() {\n\t\t\tServer server = null;\n\t\t\ttry {\n\t\t\t\tif (defaultServer == null) {\n\t\t\t\t\tserver = Server\n\t\t\t\t\t\t.createTcpServer(\"-ifNotExists\", \"-tcp\", \"-tcpAllowOthers\", \"-tcpPort\",\n\t\t\t\t\t\t\t\tString.valueOf(randomPort))\n\t\t\t\t\t\t.start();\n\t\t\t\t\tdefaultServer = server;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (SQLException e) {\n\t\t\t\tthrow new IllegalStateException(e);\n\t\t\t}\n\t\t\treturn defaultServer;\n\t\t}\n\n\t\t@Bean\n\t\tpublic Server initSecondH2TCPServer() {\n\t\t\tServer server = null;\n\t\t\ttry {\n\t\t\t\tif (secondServer == null) {\n\t\t\t\t\tserver = Server\n\t\t\t\t\t\t.createTcpServer(\"-ifNotExists\", \"-tcp\", \"-tcpAllowOthers\", \"-tcpPort\",\n\t\t\t\t\t\t\t\tString.valueOf(secondRandomPort))\n\t\t\t\t\t\t.start();\n\t\t\t\t\tsecondServer = server;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (SQLException e) {\n\t\t\t\tthrow new IllegalStateException(e);\n\t\t\t}\n\t\t\treturn secondServer;\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/multiple-datasources/src/test/resources/application.properties",
    "content": "#\n# Copyright 2016-2019 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nspring.application.name=Demo Multiple DataSources Task\nlogging.level.org.springframework.cloud.task=DEBUG\n"
  },
  {
    "path": "spring-cloud-task-samples/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<artifactId>spring-cloud-task-samples</artifactId>\n\t<packaging>pom</packaging>\n\t<name>Spring Cloud Task Samples</name>\n\n\n\t<parent>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<artifactId>spring-cloud-task-parent</artifactId>\n\t\t<version>5.0.2-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>17</java.version>\n\t</properties>\n\n\t<modules>\n\t\t<module>timestamp</module>\n\t\t<module>batch-job</module>\n\t\t<module>task-events</module>\n\t\t<module>batch-events</module>\n\t\t<module>jpa-sample</module>\n\t\t<module>task-observations</module>\n\t\t<module>multiple-datasources</module>\n\t\t<module>single-step-batch-job</module>\n\t</modules>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<!--skip deploy (this is just a test module) -->\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/.mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/README.adoc",
    "content": "= Single Step Batch Job\n\nThis is a Spring Cloud Task application that autoconfigures a single step Spring Batch job based on the profiles that are active.\n\nThe profiles that are available are:\n\n* `ffreader` - Activates a FlatFileItemReader that reads from the `test.txt` file provided.\n* `ffwriter` - Activates a FlatFileItemWriter that writes to the `result.txt` file.\n* `jdbcreader` - Activates a JdbcCursorItemReader that reads from the `item_sample` table.\n* `jdbcwriter` - Activates a JdbcItemReader that writes to the `item` table.\n* `amqpreader` - Activates a AmqpItemReader that reads from the `samplequeue` queue.\n* `amqpwriter` - Activates a AmqpItemWriter that writes to the `sampleexchange` exchange.\n* `kafkareader` - Activates a KafkaItemReader that reads from the `sampletopic` topic.\n* `kafkawriter` - Activates a KafkaItemWriter that writes to the `sampletopic` topic.\n\n== Requirements:\n\n* Java 17 or Above\n\n== Classes:\n\n* SingleStepBatchJobApplication - the Spring Boot Main Application\n\n== Build:\n\n[source,shell]\n----\nmvn clean package\n----\n\n== Run:\n\n[source,shell]\n----\njava -jar target/single-step-batch-job-5.0.0-SNAPSHOT.jar --spring.config.name=<property file containing batch, reader, and writer properties>\n----\n\n== Examples\n\n=== FlatFileItemReader with a FlatFileItemWriter batch job\nIn this example the batch job will read from the test.txt file from the resources directory and write a `result.txt` file to the root directory of the project.\n```\njava -Dspring.profiles.active=ffreader,ffwriter -jar target/single-step-batch-job-5.0.0-SNAPSHOT.jar\n```\n\n=== FlatFileItemReader with a JdbcItemWriter batch job\nIn this example the batch job will read from the test.txt file from the resources directory and write the result to the `item` table in your data store.\n```\njava -Dspring.profiles.active=ffreader,jdbcwriter -jar target/single-step-batch-job-5.0.0-SNAPSHOT.jar\n```\n\nBefore running create the following table:\n```\nCREATE TABLE IF NOT EXISTS item\n(\n   item_name varchar(55)\n);\n```\n\n=== JdbcCursorItemReader with a JdbcItemWriter batch job\nIn this example the batch job will read from the `item_sample` table in your data store (as specified in the default `DataSource` properties) and write the result to the `item` table in your data store (as specified in the default `DataSource` properties).\n```\njava -Dspring.profiles.active=jdbcreader,jdbcwriter -jar target/single-step-batch-job-5.0.0-SNAPSHOT.jar\n```\n\nBefore running create the following tables:\n```\nCREATE TABLE IF NOT EXISTS item\n(\n   item_name varchar(55)\n);\nCREATE TABLE IF NOT EXISTS item_sample\n(\n   ITEM_NAME varchar(55)\n);\n\nINSERT INTO item_sample (item_name) VALUES ('foo');\nINSERT INTO item_sample (item_name) VALUES ('bar');\nINSERT INTO item_sample (item_name) VALUES ('baz');\nINSERT INTO item_sample (item_name) VALUES ('boo');\nINSERT INTO item_sample (item_name) VALUES ('qux');\nINSERT INTO item_sample (item_name) VALUES ('Job');\n```\n\nYou may also wish to read from and write to data sources different from the default `DataSource`.   This can be done specifying datasources for the reader and writer as follows:\n```\n# Jdbc Cursor Item Reader Data Source\nexport jdbccursoritemreader_datasource_url=<your reader database>\nexport jdbccursoritemreader_datasource_username=<your user>\nexport jdbccursoritemreader_datasource_password=<your password>\nexport jdbccursoritemreader_datasource_driverClassName=<your driver classname>\nexport spring_batch_job_jdbccursoritemreader_datasource_enable=true\n# Jdbc Batch Item Writer Data Source\nexport jdbcbatchitemwriter_datasource_url=<your writer database>\nexport jdbcbatchitemwriter_datasource_username=<your user>\nexport jdbcbatchitemwriter_datasource_password=<your password>\nexport jdbcbatchitemwriter_datasource_driverClassName=<your driver classname>\nexport spring_batch_job_jdbcbatchitemwriter_datasource_enable=true\n```\n\n=== JdbcCursorItemReader with FlatfileItemWriter batch job\nIn this example the batch job will read from the `item_sample` table in your data store and write the result to the `result.txt` file to the root directory of the project.\n```\njava -Dspring.profiles.active=jdbcreader,ffwriter -jar target/single-step-batch-job-5.0.0-SNAPSHOT.jar\n```\n\nBefore running create the following table:\n```\nCREATE TABLE IF NOT EXISTS item_sample\n(\n   ITEM_NAME varchar(55)\n);\n\nINSERT INTO item_sample (item_name) VALUES ('foo');\nINSERT INTO item_sample (item_name) VALUES ('bar');\nINSERT INTO item_sample (item_name) VALUES ('baz');\nINSERT INTO item_sample (item_name) VALUES ('boo');\nINSERT INTO item_sample (item_name) VALUES ('qux');\nINSERT INTO item_sample (item_name) VALUES ('Job');\n```\n\n=== FlatfileItemReader with AmqpItemWriter batch job\nIn this example the batch job will read from the `test.txt` file and write the result to the `sampleexchange` exchange.\n```\njava -Dspring.profiles.active=ffreader,amqpwriter -jar target/single-step-batch-job-5.0.0-SNAPSHOT.jar\n```\n\nNOTE: Before running create an exchange named `sampleexchange`.\n\n=== AmqpItemReader with FlatfileItemWriter batch job\nIn this example the batch job will read from the `samplequeue` queue and write the result to the `result.txt` in the current directory.\n```\njava -Dspring.profiles.active=amqpreader,ffwriter -jar target/single-step-batch-job-5.0.0-SNAPSHOT.jar\n```\n\nNOTE: Before running create and populate a queue named `samplequeue`.\n\n=== FlatfileItemReader with KafkaItemWriter batch job\nIn this example the batch job will read from the `test.txt` file and write the result to the `sampletopic` topic.\n```\njava -Dspring.profiles.active=ffreader,kafkawriter -jar target/single-step-batch-job-5.0.0-SNAPSHOT.jar\n```\n\nBefore running create a topic named `sampletopic`.   For example:\n```\nkafka-topics.sh --create --topic sampletopic --bootstrap-server localhost:9092\n```\n\n=== KafkaItemReader with FlatfileItemWriter batch job\nIn this example the batch job will read from the `sampletopic` topic and write the result to the `result.txt` in the current directory.\n```\njava -Dspring.profiles.active=kafkareader,ffwriter -jar target/single-step-batch-job-5.0.0-SNAPSHOT.jar\n```\n\nBefore running populate the topic named `sampletopic`.   For example populate it using the FlatfileItemReader and KafkaItemWriter from above:\n```\njava -Dspring.profiles.active=ffreader,kafkawriter -jar target/single-step-batch-job-5.0.0-SNAPSHOT.jar\n```\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/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#    https://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# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n           #\n           # Look for the Apple JDKs first to preserve the existing behaviour, and then look\n           # for the new JDKs provided by Oracle.\n           #\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L \"/Library/Java/JavaVirtualMachines/CurrentJDK\" ] ; then\n             #\n             # Oracle JDKs\n             #\n             export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -x \"/usr/libexec/java_home\" ]; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=`/usr/libexec/java_home`\n           fi\n           ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Migwn, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\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    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\nfi\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n  local basedir=$(pwd)\n  local wdir=$(pwd)\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    wdir=$(cd \"$wdir/..\"; pwd)\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} \"$@\"\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.spring.cloud</groupId>\n\t<artifactId>single-step-batch-job</artifactId>\n\t<packaging>jar</packaging>\n\t<name>Single Step Batch Job Task</name>\n\t<version>5.0.0-SNAPSHOT</version>\n\t<description>Spring Cloud Single Step Batch Job Task</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>4.0.2</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<properties>\n\t\t<spring-cloud-commons.version>5.0.2-SNAPSHOT</spring-cloud-commons.version>\n\t\t<skipInstall>true</skipInstall>\n\t</properties>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-task</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mariadb.jdbc</groupId>\n\t\t\t<artifactId>mariadb-java-client</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-batch</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-single-step-batch-job</artifactId>\n\t\t\t<version>5.0.0-SNAPSHOT</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.batch</groupId>\n\t\t\t<artifactId>spring-batch-test</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-test-support</artifactId>\n\t\t\t<version>${spring-cloud-commons.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<!--skip deploy (this is just a test module) -->\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/java/io/spring/SingleStepBatchJobApplication.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.task.configuration.EnableTask;\n\n@EnableTask\n@SpringBootApplication\npublic class SingleStepBatchJobApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(SingleStepBatchJobApplication.class, args);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/java/io/spring/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Single-step batch job sample application for Spring Cloud Task.\n */\npackage io.spring;"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/resources/application-amqpreader.properties",
    "content": "spring.batch.job.amqpitemreader.name=testreader\nspring.cloud.task.closecontextEnabled=true\nspring.batch.job.amqpitemreader.enabled=true\nspring.rabbitmq.template.defaultReceiveQueue=samplequeue\nspring.rabbitmq.host=localhost\nspring.rabbitmq.port=5672\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/resources/application-amqpwriter.properties",
    "content": "spring.batch.job.amqpitemwriter.enabled=true\nspring.cloud.task.closecontextEnabled=true\nspring.rabbitmq.template.exchange=sampleexchange\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/resources/application-ffreader.properties",
    "content": "spring.batch.job.flatfileitemreader.savestate=true\nspring.batch.job.flatfileitemreader.name=fixedWidthConfiguration\nspring.batch.job.flatfileitemreader.comments=#,$\nspring.batch.job.flatfileitemreader.resource=/test.txt\nspring.batch.job.flatfileitemreader.strict=true\nspring.batch.job.flatfileitemreader.fixedLength=true\nspring.batch.job.flatfileitemreader.ranges=1-3\nspring.batch.job.flatfileitemreader.names=ITEM_NAME\nspring.batch.job.flatfileitemreader.parsingStrict=false\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/resources/application-ffwriter.properties",
    "content": "spring.batch.job.flatfileitemwriter.name=fooWriter\nspring.batch.job.flatfileitemwriter.resource=file:result.txt\nspring.batch.job.flatfileitemwriter.encoding=UTF-16\nspring.batch.job.flatfileitemwriter.saveState=false\nspring.batch.job.flatfileitemwriter.shouldDeleteIfEmpty=true\nspring.batch.job.flatfileitemwriter.delimited=true\nspring.batch.job.flatfileitemwriter.names=ITEM_NAME\nspring.batch.job.flatfileitemwriter.append=true\nspring.batch.job.flatfileitemwriter.forceSync=true\nspring.batch.job.flatfileitemwriter.shouldDeleteIfExists=false\nspring.batch.job.flatfileitemwriter.transactional=false\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/resources/application-jdbcreader.properties",
    "content": "spring.batch.job.jdbccursoritemreader.name=fooReader\nspring.batch.job.jdbccursoritemreader.sql=select item_name from item_sample order by item_name\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/resources/application-jdbcwriter.properties",
    "content": "spring.batch.job.jdbcbatchitemwriter.name=jdbcWriter\nspring.batch.job.jdbcbatchitemwriter.sql=INSERT INTO item (item_name) VALUES (:ITEM_NAME)\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/resources/application-kafkareader.properties",
    "content": "spring.kafka.consumer.bootstrapServers=localhost:9092\nspring.batch.job.kafkaitemreader.name=testreader\nspring.kafka.consumer.groupId=1\nspring.kafka.consumer.bootstrapServers=localhost:9092\nspring.kafka.consumer.valueDeserializer=org.springframework.kafka.support.serializer.JsonDeserializer\nspring.kafka.consumer.keyDeserializer=org.springframework.kafka.support.serializer.JsonDeserializer\nspring.batch.job.kafkaitemreader.topic=sampletopic\nspring.batch.job.kafkaitemreader.pollTimeOutInSeconds=2\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/resources/application-kafkawriter.properties",
    "content": "spring.kafka.producer.bootstrapServers=localhost:9092\nspring.kafka.producer.keySerializer=org.springframework.kafka.support.serializer.JsonSerializer\nspring.kafka.producer.valueSerializer=org.springframework.kafka.support.serializer.JsonSerializer\nspring.batch.job.kafkaitemwriter.topic=sampletopic\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/resources/application.properties",
    "content": "spring.application.name=Single Step Batch Job\nspring.batch.job.jobName=job\nspring.batch.job.stepName=step1\nspring.batch.job.chunkSize=5\nspring.batch.jdbc.initialize-schema=always\nlogging.level.org.springframework.cloud.task=debug\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/main/resources/test.txt",
    "content": "foo\nbar\nbaz\nqux\nboo\nJob\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/test/java/io/spring/BatchJobApplicationTests.java",
    "content": "/*\n * Copyright 2020-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport java.io.File;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.sql.SQLException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.sql.DataSource;\n\nimport org.assertj.core.api.Assertions;\nimport org.h2.tools.Server;\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.jdbc.DataSourceBuilder;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.core.io.FileSystemResource;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.jdbc.datasource.DriverManagerDataSource;\nimport org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;\nimport org.springframework.test.util.TestSocketUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Verifies that the SingleStepBatch Job for various scenarios are created properly.\n *\n * @author Glenn Renfro\n */\npublic class BatchJobApplicationTests {\n\n\tprivate final static String DATASOURCE_URL;\n\n\tprivate final static String DATASOURCE_USER_NAME = \"SA\";\n\n\tprivate final static String DATASOURCE_USER_PASSWORD = \"''\";\n\n\tprivate final static String DATASOURCE_DRIVER_CLASS_NAME = \"org.h2.Driver\";\n\n\tprivate static int randomPort;\n\n\tprivate static Server defaultServer;\n\n\tstatic {\n\t\trandomPort = TestSocketUtils.findAvailableTcpPort();\n\t\tDATASOURCE_URL = \"jdbc:h2:tcp://localhost:\" + randomPort + \"/mem:dataflow;DB_CLOSE_DELAY=-1;\"\n\t\t\t\t+ \"DB_CLOSE_ON_EXIT=FALSE\";\n\t}\n\n\tprivate File outputFile;\n\n\t@BeforeEach\n\tpublic void setup() throws Exception {\n\t\toutputFile = new File(\"result.txt\");\n\t\tinitH2TCPServer();\n\t}\n\n\t@AfterEach\n\tpublic void tearDown() throws Exception {\n\t\tFiles.deleteIfExists(Paths.get(outputFile.getAbsolutePath()));\n\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\tdataSource.setDriverClassName(DATASOURCE_DRIVER_CLASS_NAME);\n\t\tdataSource.setUrl(DATASOURCE_URL);\n\t\tdataSource.setUsername(DATASOURCE_USER_NAME);\n\t\tdataSource.setPassword(DATASOURCE_USER_PASSWORD);\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\tjdbcTemplate.execute(\"TRUNCATE TABLE item\");\n\t}\n\n\t@Test\n\tpublic void testFileReaderJdbcWriter() throws Exception {\n\t\tgetSpringApplication().run(SingleStepBatchJobApplication.class, \"--spring.profiles.active=ffreader,jdbcwriter\",\n\t\t\t\t\"--spring.datasource.username=\" + DATASOURCE_USER_NAME, \"--spring.datasource.url=\" + DATASOURCE_URL,\n\t\t\t\t\"--spring.datasource.driver-class-name=\" + DATASOURCE_DRIVER_CLASS_NAME,\n\t\t\t\t\"--spring.datasource.password=\" + DATASOURCE_USER_PASSWORD, \"foo=testFileReaderJdbcWriter\");\n\t\tvalidateDBResult();\n\t}\n\n\t@Test\n\tpublic void testJdbcReaderJdbcWriter() throws Exception {\n\t\tgetSpringApplication().run(SingleStepBatchJobApplication.class,\n\t\t\t\t\"--spring.profiles.active=jdbcreader,jdbcwriter\",\n\t\t\t\t\"--spring.datasource.username=\" + DATASOURCE_USER_NAME, \"--spring.datasource.url=\" + DATASOURCE_URL,\n\t\t\t\t\"--spring.datasource.driver-class-name=\" + DATASOURCE_DRIVER_CLASS_NAME,\n\t\t\t\t\"--spring.datasource.password=\" + DATASOURCE_USER_PASSWORD, \"foo=testJdbcReaderJdbcWriter\");\n\t\tvalidateDBResult();\n\t}\n\n\t@Test\n\tpublic void testJdbcReaderFlatfileWriter() throws Exception {\n\t\tgetSpringApplication().run(SingleStepBatchJobApplication.class, \"--spring.profiles.active=jdbcreader,ffwriter\",\n\t\t\t\t\"--spring.datasource.username=\" + DATASOURCE_USER_NAME, \"--spring.datasource.url=\" + DATASOURCE_URL,\n\t\t\t\t\"--spring.datasource.driver-class-name=\" + DATASOURCE_DRIVER_CLASS_NAME,\n\t\t\t\t\"--spring.datasource.password=\" + DATASOURCE_USER_PASSWORD, \"foo=testJdbcReaderFlatfileWriter\");\n\t\tvalidateFileResult();\n\t}\n\n\t@Test\n\tpublic void testFileReaderFileWriter() throws Exception {\n\t\tgetSpringApplication().run(SingleStepBatchJobApplication.class, \"--spring.profiles.active=ffreader,ffwriter\",\n\t\t\t\t\"foo=testFileReaderFileWriter\");\n\t\tvalidateFileResult();\n\t}\n\n\tpublic Server initH2TCPServer() throws SQLException {\n\t\tServer server;\n\n\t\tif (defaultServer == null) {\n\t\t\tserver = Server\n\t\t\t\t.createTcpServer(\"-ifNotExists\", \"-tcp\", \"-tcpAllowOthers\", \"-tcpPort\", String.valueOf(randomPort))\n\t\t\t\t.start();\n\t\t\tdefaultServer = server;\n\t\t\tDriverManagerDataSource dataSource = new DriverManagerDataSource();\n\t\t\tdataSource.setDriverClassName(DATASOURCE_DRIVER_CLASS_NAME);\n\t\t\tdataSource.setUrl(DATASOURCE_URL);\n\t\t\tdataSource.setUsername(DATASOURCE_USER_NAME);\n\t\t\tdataSource.setPassword(DATASOURCE_USER_PASSWORD);\n\t\t\tClassPathResource setupResource = new ClassPathResource(\"schema-h2.sql\");\n\t\t\tResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator(setupResource);\n\t\t\tresourceDatabasePopulator.execute(dataSource);\n\t\t}\n\n\t\treturn defaultServer;\n\t}\n\n\tprivate void validateFileResult() throws Exception {\n\t\tassertThat(Assertions.linesOf(this.outputFile, StandardCharsets.UTF_16).size()).isEqualTo(6);\n\t\tassertThat(Assertions.contentOf((new ClassPathResource(\"testresult.txt\")).getFile())\n\t\t\t.equals(new FileSystemResource(this.outputFile)));\n\t}\n\n\tprivate void validateDBResult() {\n\t\tDataSource dataSource = getDataSource();\n\t\tJdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);\n\t\tList<Map<String, Object>> result = jdbcTemplate.queryForList(\"SELECT item_name FROM item ORDER BY item_name\");\n\t\tassertThat(result.size()).isEqualTo(6);\n\n\t\tassertThat(result.get(0).get(\"item_name\")).isEqualTo(\"Job\");\n\t\tassertThat(result.get(1).get(\"item_name\")).isEqualTo(\"bar\");\n\t\tassertThat(result.get(2).get(\"item_name\")).isEqualTo(\"baz\");\n\t\tassertThat(result.get(3).get(\"item_name\")).isEqualTo(\"boo\");\n\t\tassertThat(result.get(4).get(\"item_name\")).isEqualTo(\"foo\");\n\t\tassertThat(result.get(5).get(\"item_name\")).isEqualTo(\"qux\");\n\t}\n\n\tprivate DataSource getDataSource() {\n\t\tDataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();\n\t\tdataSourceBuilder.driverClassName(DATASOURCE_DRIVER_CLASS_NAME);\n\t\tdataSourceBuilder.url(DATASOURCE_URL);\n\t\tdataSourceBuilder.username(DATASOURCE_USER_NAME);\n\t\tdataSourceBuilder.password(DATASOURCE_USER_PASSWORD);\n\t\treturn dataSourceBuilder.build();\n\t}\n\n\tprivate SpringApplication getSpringApplication() {\n\t\tSpringApplication springApplication = new SpringApplication();\n\t\tMap<String, Object> properties = new HashMap<>();\n\t\tproperties.put(\"spring.application.name\", \"Single Step Batch Job\");\n\t\tproperties.put(\"spring.batch.job.jobName\", \"job\");\n\t\tproperties.put(\"spring.batch.job.stepName\", \"step1\");\n\t\tproperties.put(\"spring.batch.job.chunkSize\", \"5\");\n\t\tspringApplication.setDefaultProperties(properties);\n\t\treturn springApplication;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/test/resources/schema-h2.sql",
    "content": "CREATE TABLE IF NOT EXISTS item\n(\n   item_name varchar(55)\n);\n\nCREATE TABLE IF NOT EXISTS item_sample\n(\n   item_name varchar(55)\n);\n\nINSERT INTO item_sample (item_name) VALUES ('foo');\nINSERT INTO item_sample (item_name) VALUES ('bar');\nINSERT INTO item_sample (item_name) VALUES ('baz');\nINSERT INTO item_sample (item_name) VALUES ('boo');\nINSERT INTO item_sample (item_name) VALUES ('qux');\nINSERT INTO item_sample (item_name) VALUES ('Job');\n"
  },
  {
    "path": "spring-cloud-task-samples/single-step-batch-job/src/test/resources/test.txt",
    "content": "Job\nbar\nbaz\nboo\nfoo\nqux\n"
  },
  {
    "path": "spring-cloud-task-samples/task-events/.mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip\n"
  },
  {
    "path": "spring-cloud-task-samples/task-events/README.adoc",
    "content": "= Task Events\n\nThis is a task application that emits events on a channel named `task-events`\n\n== Requirements:\n\n* Java 17 or Above\n\n== Build:\n\n[source,shell]\n----\n./mvnw clean install\n----\n\n== Execution:\n\n[source,shell]\n----\njava -jar target/task-events-5.0.0.RELEASE.jar\n----\n\nYou can listen for the events on the task-events channel with a Spring Cloud Stream Sink\nlike the https://github.com/spring-cloud/stream-applications/tree/main/applications/sink/log-sink[log sink] using the following:\n\n[source,shell]\n----\njava -jar <PATH_TO_LOG_SINK_JAR>/log-sink-rabbit-3.1.2.jar --server.port=9090 --spring.cloud.stream.bindings.input.destination=task-events\n----\n\n== Dependencies:\n\nThe task-events sample requires an instance of RabbitMQ to be running.\n"
  },
  {
    "path": "spring-cloud-task-samples/task-events/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#    https://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# Maven2 Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n           #\n           # Look for the Apple JDKs first to preserve the existing behaviour, and then look\n           # for the new JDKs provided by Oracle.\n           #\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -L \"/Library/Java/JavaVirtualMachines/CurrentJDK\" ] ; then\n             #\n             # Oracle JDKs\n             #\n             export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home\n           fi\n\n           if [ -z \"$JAVA_HOME\" ] && [ -x \"/usr/libexec/java_home\" ]; then\n             #\n             # Apple JDKs\n             #\n             export JAVA_HOME=`/usr/libexec/java_home`\n           fi\n           ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Migwn, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\n  # TODO classpath?\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\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    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`which java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\nfi\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n  local basedir=$(pwd)\n  local wdir=$(pwd)\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    wdir=$(cd \"$wdir/..\"; pwd)\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} \"$@\"\n"
  },
  {
    "path": "spring-cloud-task-samples/task-events/mvnw.cmd",
    "content": "@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    https://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 Maven2 Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_pre.bat\" call \"%HOME%\\mavenrc_pre.bat\"\nif exist \"%HOME%\\mavenrc_pre.cmd\" call \"%HOME%\\mavenrc_pre.cmd\"\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\nset MAVEN_CMD_LINE_ARGS=%*\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\n\nset WRAPPER_JAR=\"\".\\.mvn\\wrapper\\maven-wrapper.jar\"\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%HOME%\\mavenrc_post.bat\" call \"%HOME%\\mavenrc_post.bat\"\nif exist \"%HOME%\\mavenrc_post.cmd\" call \"%HOME%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\" == \"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\" == \"on\" exit %ERROR_CODE%\n\nexit /B %ERROR_CODE%"
  },
  {
    "path": "spring-cloud-task-samples/task-events/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.spring.cloud</groupId>\n\t<artifactId>task-events</artifactId>\n\t<version>5.0.0-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<name>Task Events</name>\n\t<description>Demo of publishing task events to Spring Cloud Streams</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>4.0.2</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<java.version>17</java.version>\n\t\t<spring-cloud-stream.version>5.0.2-SNAPSHOT</spring-cloud-stream.version>\n\t</properties>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-stream-dependencies</artifactId>\n\t\t\t\t<version>${spring-cloud-stream.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-task</artifactId>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-stream-rabbit</artifactId>\n\t\t\t<scope>compile</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<!--skip deploy (this is just a test module) -->\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n\n</project>\n"
  },
  {
    "path": "spring-cloud-task-samples/task-events/src/main/java/io/spring/TaskEventsApplication.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring;\n\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@EnableTask\n@SpringBootApplication\npublic class TaskEventsApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(TaskEventsApplication.class, args);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\tpublic static class TaskConfiguration {\n\n\t\t@Bean\n\t\tpublic CommandLineRunner commandLineRunner() {\n\t\t\treturn new CommandLineRunner() {\n\t\t\t\t@Override\n\t\t\t\tpublic void run(String... args) throws Exception {\n\t\t\t\t\tSystem.out.println(\"The CommandLineRunner was executed\");\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/task-events/src/main/java/io/spring/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Task events sample application for Spring Cloud Task.\n */\npackage io.spring;"
  },
  {
    "path": "spring-cloud-task-samples/task-events/src/main/resources/application.properties",
    "content": "spring.application.name=Event Emitting Task\nlogging.level.org.springframework.cloud.stream=DEBUG\nlogging.level.org.springframework.cloud.task=DEBUG\n\n"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/.gitignore",
    "content": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n.sts4-cache\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\n/nbproject/private/\n/nbbuild/\n/dist/\n/nbdist/\n/.nb-gradle/\nbuild/\n!**/src/main/**/build/\n!**/src/test/**/build/\n\n### VS Code ###\n.vscode/\n"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/.mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip\nwrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar\n"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/README.adoc",
    "content": "= Timestamp Task\n\nThis is a Spring Cloud Task application that utilizes Micrometer and displays\nmetrics at the end of the application using the SimpleMeterRegistry.\n\n== Requirements:\n\n* Java 17 or Above\n\n== Classes:\n\n* TaskObservationsApplication - the Spring Boot Main Application\n\n== Build:\n\n[source,shell]\n----\nmvn clean package\n----\n\n== Run:\n\n[source,shell]\n----\njava -jar target/task-observations-5.0.0.jar\n----\n\n== Native Build:\n\n[source,shell]\n----\nmvn -Pnative clean package\n----\n\n== Native Run:\n\n[source,shell]\n----\n./target/task-observations\n----\n"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/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#    https://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# Maven Start Up Batch script\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   M2_HOME - location of maven2's installed home dir\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /usr/local/etc/mavenrc ] ; then\n    . /usr/local/etc/mavenrc\n  fi\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"`uname`\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        export JAVA_HOME=\"`/usr/libexec/java_home`\"\n      else\n        export JAVA_HOME=\"/Library/Java/Home\"\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=`java-config --jre-home`\n  fi\nfi\n\nif [ -z \"$M2_HOME\" ] ; then\n  ## resolve links - $0 may be a link to maven's home\n  PRG=\"$0\"\n\n  # need this for relative symlinks\n  while [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n      PRG=\"$link\"\n    else\n      PRG=\"`dirname \"$PRG\"`/$link\"\n    fi\n  done\n\n  saveddir=`pwd`\n\n  M2_HOME=`dirname \"$PRG\"`/..\n\n  # make it fully qualified\n  M2_HOME=`cd \"$M2_HOME\" && pwd`\n\n  cd \"$saveddir\"\n  # echo Using m2 at $M2_HOME\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --unix \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --unix \"$CLASSPATH\"`\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=\"`(cd \"$M2_HOME\"; pwd)`\"\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"`(cd \"$JAVA_HOME\"; pwd)`\"\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"`which javac`\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"`expr \\\"$javaExecutable\\\" : '\\([^ ]*\\)'`\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=`which readlink`\n    if [ ! `expr \"$readLink\" : '\\([^ ]*\\)'` = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n        javaExecutable=\"`cd \\\"$javaHome\\\" && pwd -P`/javac\"\n      else\n        javaExecutable=\"`readlink -f \\\"$javaExecutable\\\"`\"\n      fi\n      javaHome=\"`dirname \\\"$javaExecutable\\\"`\"\n      javaHome=`expr \"$javaHome\" : '\\(.*\\)/bin'`\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\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    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"`\\\\unset -f command; \\\\command -v java`\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\nCLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=`cd \"$wdir/..\"; pwd`\n    fi\n    # end of workaround\n  done\n  echo \"${basedir}\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    echo \"$(tr -s '\\n' ' ' < \"$1\")\"\n  fi\n}\n\nBASE_DIR=`find_maven_basedir \"$(pwd)\"`\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nif [ -r \"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\" ]; then\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Found .mvn/wrapper/maven-wrapper.jar\"\n    fi\nelse\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ...\"\n    fi\n    if [ -n \"$MVNW_REPOURL\" ]; then\n      jarUrl=\"$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar\"\n    else\n      jarUrl=\"https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar\"\n    fi\n    while IFS=\"=\" read key value; do\n      case \"$key\" in (wrapperUrl) jarUrl=\"$value\"; break ;;\n      esac\n    done < \"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties\"\n    if [ \"$MVNW_VERBOSE\" = true ]; then\n      echo \"Downloading from: $jarUrl\"\n    fi\n    wrapperJarPath=\"$BASE_DIR/.mvn/wrapper/maven-wrapper.jar\"\n    if $cygwin; then\n      wrapperJarPath=`cygpath --path --windows \"$wrapperJarPath\"`\n    fi\n\n    if command -v wget > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found wget ... using wget\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            wget \"$jarUrl\" -O \"$wrapperJarPath\" || rm -f \"$wrapperJarPath\"\n        else\n            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD \"$jarUrl\" -O \"$wrapperJarPath\" || rm -f \"$wrapperJarPath\"\n        fi\n    elif command -v curl > /dev/null; then\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Found curl ... using curl\"\n        fi\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            curl -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        else\n            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o \"$wrapperJarPath\" \"$jarUrl\" -f\n        fi\n\n    else\n        if [ \"$MVNW_VERBOSE\" = true ]; then\n          echo \"Falling back to using Java to download\"\n        fi\n        javaClass=\"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        # For Cygwin, switch paths to Windows format before running javac\n        if $cygwin; then\n          javaClass=`cygpath --path --windows \"$javaClass\"`\n        fi\n        if [ -e \"$javaClass\" ]; then\n            if [ ! -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Compiling MavenWrapperDownloader.java ...\"\n                fi\n                # Compiling the Java class\n                (\"$JAVA_HOME/bin/javac\" \"$javaClass\")\n            fi\n            if [ -e \"$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class\" ]; then\n                # Running the downloader\n                if [ \"$MVNW_VERBOSE\" = true ]; then\n                  echo \" - Running MavenWrapperDownloader.java ...\"\n                fi\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$MAVEN_PROJECTBASEDIR\")\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\nexport MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}\nif [ \"$MVNW_VERBOSE\" = true ]; then\n  echo $MAVEN_PROJECTBASEDIR\nfi\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$M2_HOME\" ] &&\n    M2_HOME=`cygpath --path --windows \"$M2_HOME\"`\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=`cygpath --path --windows \"$JAVA_HOME\"`\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=`cygpath --path --windows \"$CLASSPATH\"`\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=`cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\"`\nfi\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $@\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  $MAVEN_DEBUG_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.home=${M2_HOME}\" \\\n  \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/mvnw.cmd",
    "content": "@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    https://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 Maven Start Up Batch script\n@REM\n@REM Required ENV vars:\n@REM JAVA_HOME - location of a JDK home dir\n@REM\n@REM Optional ENV vars\n@REM M2_HOME - location of maven2's installed home dir\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\n@REM     e.g. to debug Maven itself, use\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n@REM ----------------------------------------------------------------------------\n\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\n@echo off\n@REM set title of command window\ntitle %0\n@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\n\n@REM set %HOME% to equivalent of $HOME\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\n\n@REM Execute a user defined script before this one\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\nif exist \"%USERPROFILE%\\mavenrc_pre.bat\" call \"%USERPROFILE%\\mavenrc_pre.bat\" %*\nif exist \"%USERPROFILE%\\mavenrc_pre.cmd\" call \"%USERPROFILE%\\mavenrc_pre.cmd\" %*\n:skipRcPre\n\n@setlocal\n\nset ERROR_CODE=0\n\n@REM To isolate internal variables from possible post scripts, we use another setlocal\n@setlocal\n\n@REM ==== START VALIDATION ====\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\n\necho.\necho Error: JAVA_HOME not found in your environment. >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n:OkJHome\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\n\necho.\necho Error: JAVA_HOME is set to an invalid directory. >&2\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\necho Please set the JAVA_HOME variable in your environment to match the >&2\necho location of your Java installation. >&2\necho.\ngoto error\n\n@REM ==== END VALIDATION ====\n\n:init\n\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\n@REM Fallback to current working directory if not found.\n\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\n\nset EXEC_DIR=%CD%\nset WDIR=%EXEC_DIR%\n:findBaseDir\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\ncd ..\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\nset WDIR=%CD%\ngoto findBaseDir\n\n:baseDirFound\nset MAVEN_PROJECTBASEDIR=%WDIR%\ncd \"%EXEC_DIR%\"\ngoto endDetectBaseDir\n\n:baseDirNotFound\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\ncd \"%EXEC_DIR%\"\n\n:endDetectBaseDir\n\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\n\n@setlocal EnableExtensions EnableDelayedExpansion\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\n\n:endReadAdditionalConfig\n\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\nset DOWNLOAD_URL=\"https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar\"\n\nFOR /F \"usebackq tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\n    IF \"%%A\"==\"wrapperUrl\" SET DOWNLOAD_URL=%%B\n)\n\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\nif exist %WRAPPER_JAR% (\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Found %WRAPPER_JAR%\n    )\n) else (\n    if not \"%MVNW_REPOURL%\" == \"\" (\n        SET DOWNLOAD_URL=\"%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar\"\n    )\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Couldn't find %WRAPPER_JAR%, downloading it ...\n        echo Downloading from: %DOWNLOAD_URL%\n    )\n\n    powershell -Command \"&{\"^\n\t\t\"$webclient = new-object System.Net.WebClient;\"^\n\t\t\"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {\"^\n\t\t\"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');\"^\n\t\t\"}\"^\n\t\t\"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')\"^\n\t\t\"}\"\n    if \"%MVNW_VERBOSE%\" == \"true\" (\n        echo Finished downloading %WRAPPER_JAR%\n    )\n)\n@REM End of extension\n\n@REM Provide a \"standardized\" way to retrieve the CLI args that will\n@REM work with both Windows and non-Windows executions.\nset MAVEN_CMD_LINE_ARGS=%*\n\n%MAVEN_JAVA_EXE% ^\n  %JVM_CONFIG_MAVEN_PROPS% ^\n  %MAVEN_OPTS% ^\n  %MAVEN_DEBUG_OPTS% ^\n  -classpath %WRAPPER_JAR% ^\n  \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" ^\n  %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\nif ERRORLEVEL 1 goto error\ngoto end\n\n:error\nset ERROR_CODE=1\n\n:end\n@endlocal & set ERROR_CODE=%ERROR_CODE%\n\nif not \"%MAVEN_SKIP_RC%\"==\"\" goto skipRcPost\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\nif exist \"%USERPROFILE%\\mavenrc_post.bat\" call \"%USERPROFILE%\\mavenrc_post.bat\"\nif exist \"%USERPROFILE%\\mavenrc_post.cmd\" call \"%USERPROFILE%\\mavenrc_post.cmd\"\n:skipRcPost\n\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\nif \"%MAVEN_BATCH_PAUSE%\"==\"on\" pause\n\nif \"%MAVEN_TERMINATE_CMD%\"==\"on\" exit %ERROR_CODE%\n\ncmd /C exit /B %ERROR_CODE%\n"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n\t\t xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>io.spring</groupId>\n\t<artifactId>task-observations</artifactId>\n\t<version>5.0.0-SNAPSHOT</version>\n\t<name>task observation sample</name>\n\t<description>Displays task observations as well as commandline and application runner observations</description>\n\t<properties>\n\t\t<java.version>17</java.version>\n\t</properties>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>4.0.2</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-task</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-actuator</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.micrometer</groupId>\n\t\t\t<artifactId>micrometer-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.micrometer</groupId>\n\t\t\t<artifactId>micrometer-observation</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mariadb.jdbc</groupId>\n\t\t\t<artifactId>mariadb-java-client</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<!--skip deploy (this is just a test module) -->\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/src/main/java/io/spring/taskobservations/ObservationConfiguration.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.taskobservations;\n\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n@Configuration\npublic class ObservationConfiguration {\n\n\t@Bean\n\tpublic SimpleMeterRegistry meterRegistry() {\n\t\treturn new SimpleMeterRegistry();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/src/main/java/io/spring/taskobservations/TaskObservationsApplication.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.taskobservations;\n\nimport io.micrometer.core.instrument.simple.SimpleMeterRegistry;\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.cloud.task.listener.annotation.AfterTask;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.context.annotation.Bean;\n\n@SpringBootApplication\n@EnableTask\npublic class TaskObservationsApplication {\n\n\tprivate static final Log logger = LogFactory.getLog(TaskObservationsApplication.class);\n\n\t@Autowired\n\tpublic SimpleMeterRegistry simpleMeterRegistry;\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(TaskObservationsApplication.class, args);\n\t}\n\n\t@Bean\n\tpublic ApplicationRunner applicationRunner() {\n\t\treturn args -> logger.info(\"Hello ApplicationRunner Metric's World\");\n\t}\n\n\t@Bean\n\tpublic CommandLineRunner commandLineRunner() {\n\t\treturn args -> logger.info(\"Hello CommandLineRunner Metric's World\");\n\t}\n\n\t/**\n\t * Prints the metrics as recorded in the simpleMeterRegistry.\n\t */\n\t@AfterTask\n\tpublic void afterTask(TaskExecution taskExecution) {\n\t\tSystem.out.println(simpleMeterRegistry.getMetersAsString());\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/src/main/java/io/spring/taskobservations/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Task observations sample application for Spring Cloud Task.\n */\npackage io.spring.taskobservations;"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/src/main/resources/application.properties",
    "content": "logging.level.org.springframework.cloud.task=debug\nmanagement.metrics.tags.service=task-observations-application\nmanagement.metrics.tags.application=task-observations-application-58\nspring.cloud.task.name=taskmetrics\nspring.cloud.task.observation.enabled=true\n\n"
  },
  {
    "path": "spring-cloud-task-samples/task-observations/src/test/java/io/spring/taskobservations/TaskObservationsApplicationTests.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.spring.taskobservations;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;\n\n@SpringBootTest\n@ExtendWith(OutputCaptureExtension.class)\nclass TaskObservationsApplicationTests {\n\n\t@Test\n\tvoid contextLoads(CapturedOutput output) {\n\t\tString result = output.getAll();\n\t\tassertThat(result).contains(\"spring.cloud.task(TIMER)[application='task-observations-application-58', \"\n\t\t\t\t+ \"error='none', service='task-observations-application', \"\n\t\t\t\t+ \"spring.cloud.task.execution.id='1', spring.cloud.task.exit.code='0', \"\n\t\t\t\t+ \"spring.cloud.task.external.execution.id='unknown', spring.cloud.task.name='taskmetrics', \"\n\t\t\t\t+ \"spring.cloud.task.parent.execution.id='unknown', spring.cloud.task.status='success']; \"\n\t\t\t\t+ \"count=1.0, total_time=\");\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/timestamp/README.adoc",
    "content": "= Timestamp Task\n\nThis is a Spring Cloud Task application that logs a timestamp.\n\n== Requirements:\n\n* Java 17 or Above\n\n== Classes:\n\n* TaskApplication - the Spring Boot Main Application\n* TimestampTask - the module that writes the log entry as Spring Cloud Task\n\n== Build:\n\n[source,shell]\n----\nmvn clean package\n----\n\n== Run:\n\n[source,shell]\n----\njava -jar target/timestamp-task-5.0.0.jar\n----\n\n== Native Build:\n\n[source,shell]\n----\nmvn -Pnative native:compile\n----\n\n== Native Run:\n\n[source,shell]\n----\n./target/timestamp-task\n----\n"
  },
  {
    "path": "spring-cloud-task-samples/timestamp/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>io.spring.cloud</groupId>\n\t<artifactId>timestamp-task</artifactId>\n\t<packaging>jar</packaging>\n\t<name>Timestamp Task</name>\n\t<version>5.0.0-SNAPSHOT</version>\n\t<description>Spring Cloud Timestamp Task</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>4.0.2</version>\n\t\t<relativePath />\n\t</parent>\n\n\t<properties>\n\t\t<start-class>org.springframework.cloud.task.timestamp.TaskApplication\n\t\t</start-class>\n\t\t<skipInstall>true</skipInstall>\n\t</properties>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t\t<artifactId>spring-cloud-task-dependencies</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-task-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-jdbc</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mariadb.jdbc</groupId>\n\t\t\t<artifactId>mariadb-java-client</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.postgresql</groupId>\n\t\t\t<artifactId>postgresql</artifactId>\n\t\t</dependency>\n\t</dependencies>\n\n\t<pluginRepositories>\n\t\t<pluginRepository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t\t<pluginRepository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</pluginRepository>\n\t</pluginRepositories>\n\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>spring-snapshots</id>\n\t\t\t<name>Spring Snapshots</name>\n\t\t\t<url>https://repo.spring.io/snapshot</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-milestones</id>\n\t\t\t<name>Spring Milestones</name>\n\t\t\t<url>https://repo.spring.io/milestone</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t\t<repository>\n\t\t\t<id>spring-releases</id>\n\t\t\t<name>Spring Releases</name>\n\t\t\t<url>https://repo.spring.io/release</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>false</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-sources</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<!--skip deploy (this is just a test module) -->\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skip>true</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/TaskApplication.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.timestamp;\n\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.context.annotation.Bean;\n\n/**\n * Spring Boot Application that has tasks enabled.\n */\n@EnableTask\n@SpringBootApplication\n@EnableConfigurationProperties({ TimestampTaskProperties.class })\npublic class TaskApplication {\n\n\tprivate static final Log logger = LogFactory.getLog(TaskApplication.class);\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(TaskApplication.class, args);\n\t}\n\n\t@Bean\n\tpublic TimestampTask timeStampTask() {\n\t\treturn new TimestampTask();\n\t}\n\n\t/**\n\t * A commandline runner that prints a timestamp.\n\t */\n\tpublic static class TimestampTask implements CommandLineRunner {\n\n\t\t@Autowired\n\t\tprivate TimestampTaskProperties config;\n\n\t\t@Override\n\t\tpublic void run(String... strings) {\n\t\t\tDateFormat dateFormat = new SimpleDateFormat(this.config.getFormat());\n\t\t\tlogger.info(dateFormat.format(new Date()));\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/TimestampTaskProperties.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.timestamp;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.util.Assert;\n\n/**\n * @author Glenn Renfro\n */\n@ConfigurationProperties\npublic class TimestampTaskProperties {\n\n\t/**\n\t * The timestamp format, \"yyyy-MM-dd HH:mm:ss.SSS\" by default.\n\t */\n\tprivate String format = \"yyyy-MM-dd HH:mm:ss.SSS\";\n\n\tpublic String getFormat() {\n\t\tAssert.hasText(this.format, \"format must not be empty nor null\");\n\t\treturn this.format;\n\t}\n\n\tpublic void setFormat(String format) {\n\t\tthis.format = format;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Sample timestamp task application for Spring Cloud Task.\n */\npackage org.springframework.cloud.task.timestamp;"
  },
  {
    "path": "spring-cloud-task-samples/timestamp/src/main/resources/application.properties",
    "content": "spring.application.name=Demo Timestamp Task\nlogging.level.org.springframework.cloud.task=DEBUG\n#spring.aop.proxy-target-class=false\n\n"
  },
  {
    "path": "spring-cloud-task-samples/timestamp/src/test/java/org/springframework/cloud/task/timestamp/TaskApplicationTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.timestamp;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.test.system.CapturedOutput;\nimport org.springframework.boot.test.system.OutputCaptureExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * Verifies that the Task Application outputs the correct task log entries.\n *\n * @author Glenn Renfro\n */\n@ExtendWith(OutputCaptureExtension.class)\npublic class TaskApplicationTests {\n\n\t@Test\n\tpublic void testTimeStampApp(CapturedOutput capturedOutput) throws Exception {\n\t\tfinal String TEST_DATE_DOTS = \".......\";\n\t\tfinal String CREATE_TASK_MESSAGE = \"Creating: TaskExecution{executionId=\";\n\t\tfinal String UPDATE_TASK_MESSAGE = \"Updating: TaskExecution with executionId=\";\n\t\tfinal String EXIT_CODE_MESSAGE = \"with the following {exitCode=0\";\n\t\tString[] args = { \"--format=yyyy\" + TEST_DATE_DOTS };\n\n\t\tSpringApplication.run(TaskApplication.class, args);\n\n\t\tString output = capturedOutput.toString();\n\t\tassertThat(output.contains(TEST_DATE_DOTS)).as(\"Unable to find the timestamp: \" + output).isTrue();\n\t\tassertThat(output.contains(CREATE_TASK_MESSAGE)).as(\"Test results do not show create task message: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(UPDATE_TASK_MESSAGE)).as(\"Test results do not show success message: \" + output)\n\t\t\t.isTrue();\n\t\tassertThat(output.contains(EXIT_CODE_MESSAGE)).as(\"Test results have incorrect exit code: \" + output).isTrue();\n\n\t\tString taskTitle = \" taskName='Demo Timestamp Task'\";\n\t\tPattern pattern = Pattern.compile(taskTitle);\n\t\tMatcher matcher = pattern.matcher(output);\n\t\tint count = 0;\n\t\twhile (matcher.find()) {\n\t\t\tcount++;\n\t\t}\n\t\tassertThat(count).as(\"The number of task titles did not match expected: \").isEqualTo(1);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/timestamp/src/test/java/org/springframework/cloud/task/timestamp/TimestampTaskPropertiesTests.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.timestamp;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.boot.test.util.TestPropertyValues;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\nimport org.springframework.context.annotation.Configuration;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatExceptionOfType;\n\n/**\n * @author Glenn Renfro\n */\npublic class TimestampTaskPropertiesTests {\n\n\t@Test\n\tpublic void testEmptyFormat() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tTestPropertyValues testPropertyValues = TestPropertyValues.of(\"format:\");\n\t\ttestPropertyValues.applyTo(context);\n\t\tcontext.register(Conf.class);\n\t\tcontext.refresh();\n\t\tTimestampTaskProperties properties = context.getBean(TimestampTaskProperties.class);\n\t\tassertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {\n\t\t\tproperties.getFormat();\n\t\t});\n\t}\n\n\t@Test\n\tpublic void testFormatDefault() {\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.register(Conf.class);\n\t\tcontext.refresh();\n\t\tTimestampTaskProperties properties = context.getBean(TimestampTaskProperties.class);\n\t\tassertThat(properties.getFormat()).as(\"result does not match default format.\")\n\t\t\t.isEqualTo(\"yyyy-MM-dd HH:mm:ss.SSS\");\n\t}\n\n\t@Test\n\tpublic void testFormatSet() {\n\t\tfinal String FORMAT = \"yyyy\";\n\t\tAnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();\n\t\tcontext.register(Conf.class);\n\t\tcontext.refresh();\n\t\tTimestampTaskProperties properties = context.getBean(TimestampTaskProperties.class);\n\t\tproperties.setFormat(FORMAT);\n\t\tassertThat(properties.getFormat()).as(\"result does not match established format.\").isEqualTo(FORMAT);\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableConfigurationProperties(TimestampTaskProperties.class)\n\tstatic class Conf {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-samples/timestamp/src/test/resources/application.properties",
    "content": "#\n# Copyright 2016-2019 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\nlogging.level.org.springframework.cloud.task=DEBUG\nspring.application.name=Demo Timestamp Task\n"
  },
  {
    "path": "spring-cloud-task-stream/.mvn/wrapper/maven-wrapper.properties",
    "content": "distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip\n"
  },
  {
    "path": "spring-cloud-task-stream/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<artifactId>spring-cloud-task-stream</artifactId>\n\t<packaging>jar</packaging>\n\t<name>Spring Cloud Task Stream</name>\n\t<description>Allows a Task to be a part of a stream</description>\n\n\t<parent>\n\t\t<groupId>org.springframework.cloud</groupId>\n\t\t<artifactId>spring-cloud-task-parent</artifactId>\n\t\t<version>5.0.2-SNAPSHOT</version>\n\t</parent>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.batch</groupId>\n\t\t\t<artifactId>spring-batch-core</artifactId>\n\t\t\t<optional>true</optional>\n\t\t\t<exclusions>\n\t\t\t\t<exclusion>\n\t\t\t\t\t<groupId>org.springframework</groupId>\n\t\t\t\t\t<artifactId>spring-core</artifactId>\n\t\t\t\t</exclusion>\n\t\t\t</exclusions>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-stream</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-task-core</artifactId>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>tools.jackson.core</groupId>\n\t\t\t<artifactId>jackson-databind</artifactId>\n\t\t\t<scope>test</scope>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-starter-stream-rabbit</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId>spring-cloud-task-batch</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.h2database</groupId>\n\t\t\t<artifactId>h2</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-configuration-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-autoconfigure-processor</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.cloud</groupId>\n\t\t\t<artifactId> spring-cloud-stream-test-binder</artifactId>\n\t\t\t<version>${spring-cloud-stream.version}</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.assertj</groupId>\n\t\t\t<artifactId>assertj-core</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/BatchEventAutoConfiguration.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.springframework.batch.core.job.Job;\nimport org.springframework.batch.core.listener.ItemProcessListener;\nimport org.springframework.batch.core.listener.ItemReadListener;\nimport org.springframework.batch.core.listener.ItemWriteListener;\nimport org.springframework.batch.core.listener.JobExecutionListener;\nimport org.springframework.batch.core.listener.SkipListener;\nimport org.springframework.batch.core.listener.StepExecutionListener;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.cloud.stream.function.StreamBridge;\nimport org.springframework.cloud.task.batch.listener.support.MessagePublisher;\nimport org.springframework.cloud.task.batch.listener.support.TaskBatchEventListenerBeanPostProcessor;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.listener.TaskLifecycleListener;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Lazy;\n\n/**\n * Autoconfigures Spring Batch listeners designed to emit events on the following\n * channels.\n *\n * <ul>\n * <li>{@link EventEmittingJobExecutionListener} - job-execution-events</li>\n * <li>{@link EventEmittingStepExecutionListener} - step-execution-events</li>\n * <li>{@link org.springframework.batch.core.listener.ChunkListener} - chunk-events</li>\n * <li>{@link EventEmittingItemReadListener} - item-read-events</li>\n * <li>{@link EventEmittingItemProcessListener} - item-process-events</li>\n * <li>{@link EventEmittingItemWriteListener} - item-write-events</li>\n * <li>{@link EventEmittingSkipListener} - skip-events</li>\n * </ul>\n *\n * @author Michael Minella\n * @author Glenn Renfro\n * @author Ali Shahbour\n */\n// @checkstyle:off\n@AutoConfiguration(after = SimpleTaskAutoConfiguration.class)\n@ConditionalOnClass(Job.class)\n@ConditionalOnBean({ Job.class, TaskLifecycleListener.class })\n@ConditionalOnProperty(prefix = \"spring.cloud.task.batch.events\", name = \"enabled\", havingValue = \"true\",\n\t\tmatchIfMissing = true)\n// @checkstyle:on\npublic class BatchEventAutoConfiguration {\n\n\t/**\n\t * Name of the job execution events listener bean.\n\t */\n\tpublic static final String JOB_EXECUTION_EVENTS_LISTENER = \"jobExecutionEventsListener\";\n\n\t/**\n\t * Name of the chunk events listener bean.\n\t */\n\tpublic static final String CHUNK_EVENTS_LISTENER = \"chunkEventsListener\";\n\n\t/**\n\t * Name of the step execution events listener bean.\n\t */\n\tpublic static final String STEP_EXECUTION_EVENTS_LISTENER = \"stepExecutionEventsListener\";\n\n\t/**\n\t * Name of the item read events listener bean.\n\t */\n\tpublic static final String ITEM_READ_EVENTS_LISTENER = \"itemReadEventsListener\";\n\n\t/**\n\t * Name of the item write events listener bean.\n\t */\n\tpublic static final String ITEM_WRITE_EVENTS_LISTENER = \"itemWriteEventsListener\";\n\n\t/**\n\t * Name of the item process events listener bean.\n\t */\n\tpublic static final String ITEM_PROCESS_EVENTS_LISTENER = \"itemProcessEventsListener\";\n\n\t/**\n\t * Name of the skip events listener bean.\n\t */\n\tpublic static final String SKIP_EVENTS_LISTENER = \"skipEventsListener\";\n\n\t@Bean\n\t@ConditionalOnMissingBean\n\tpublic static TaskBatchEventListenerBeanPostProcessor batchTaskEventListenerBeanPostProcessor() {\n\t\treturn new TaskBatchEventListenerBeanPostProcessor();\n\t}\n\n\t/**\n\t * Configuration for Job Execution Listener.\n\t */\n\t@AutoConfiguration\n\t@ConditionalOnClass(StreamBridge.class)\n\t@EnableConfigurationProperties(TaskEventProperties.class)\n\t@ConditionalOnMissingBean(name = JOB_EXECUTION_EVENTS_LISTENER)\n\t@ConditionalOnExpression(\"T(org.springframework.util.StringUtils).isEmpty('${spring.batch.job.jobName:}')\")\n\tpublic static class JobExecutionListenerConfiguration {\n\n\t\t@Autowired\n\t\tprivate TaskEventProperties taskEventProperties;\n\n\t\t// @checkstyle:off\n\t\t@Bean\n\t\t@Lazy\n\t\t@ConditionalOnProperty(prefix = \"spring.cloud.task.batch.events.job-execution\", name = \"enabled\",\n\t\t\t\thavingValue = \"true\", matchIfMissing = true)\n\t\t// @checkstyle:on\n\t\tpublic JobExecutionListener jobExecutionEventsListener(MessagePublisher messagePublisher,\n\t\t\t\tTaskEventProperties properties) {\n\t\t\treturn new EventEmittingJobExecutionListener(messagePublisher,\n\t\t\t\t\tthis.taskEventProperties.getJobExecutionOrder(), properties);\n\t\t}\n\n\t\t// @checkstyle:off\n\t\t@Bean\n\t\t@ConditionalOnProperty(prefix = \"spring.cloud.task.batch.events.step-execution\", name = \"enabled\",\n\t\t\t\thavingValue = \"true\", matchIfMissing = true)\n\t\t// @checkstyle:on\n\t\tpublic StepExecutionListener stepExecutionEventsListener(MessagePublisher messagePublisher,\n\t\t\t\tTaskEventProperties properties) {\n\t\t\treturn new EventEmittingStepExecutionListener(messagePublisher,\n\t\t\t\t\tthis.taskEventProperties.getStepExecutionOrder(), properties);\n\t\t}\n\n\t\t// @checkstyle:off\n\t\t@Bean\n\t\t@Lazy\n\t\t@ConditionalOnProperty(prefix = \"spring.cloud.task.batch.events.chunk\", name = \"enabled\", havingValue = \"true\",\n\t\t\t\tmatchIfMissing = true)\n\t\t// @checkstyle:on\n\t\tpublic EventEmittingChunkListener chunkEventsListener(MessagePublisher messagePublisher,\n\t\t\t\tTaskEventProperties properties) {\n\t\t\treturn new EventEmittingChunkListener(messagePublisher, this.taskEventProperties.getChunkOrder(),\n\t\t\t\t\tproperties);\n\t\t}\n\n\t\t// @checkstyle:off\n\t\t@Bean\n\t\t@ConditionalOnProperty(prefix = \"spring.cloud.task.batch.events.item-read\", name = \"enabled\",\n\t\t\t\thavingValue = \"true\", matchIfMissing = true)\n\t\t// @checkstyle:on\n\t\tpublic ItemReadListener itemReadEventsListener(MessagePublisher messagePublisher,\n\t\t\t\tTaskEventProperties properties) {\n\t\t\treturn new EventEmittingItemReadListener(messagePublisher, this.taskEventProperties.getItemReadOrder(),\n\t\t\t\t\tproperties);\n\t\t}\n\n\t\t// @checkstyle:off\n\t\t@Bean\n\t\t@ConditionalOnProperty(prefix = \"spring.cloud.task.batch.events.item-write\", name = \"enabled\",\n\t\t\t\thavingValue = \"true\", matchIfMissing = true)\n\t\t// @checkstyle:on\n\t\tpublic ItemWriteListener itemWriteEventsListener(MessagePublisher messagePublisher,\n\t\t\t\tTaskEventProperties properties) {\n\t\t\treturn new EventEmittingItemWriteListener(messagePublisher, this.taskEventProperties.getItemWriteOrder(),\n\t\t\t\t\tproperties);\n\t\t}\n\n\t\t// @checkstyle:off\n\t\t@Bean\n\t\t@ConditionalOnProperty(prefix = \"spring.cloud.task.batch.events.item-process\", name = \"enabled\",\n\t\t\t\thavingValue = \"true\", matchIfMissing = true)\n\t\t// @checkstyle:on\n\t\tpublic ItemProcessListener itemProcessEventsListener(MessagePublisher messagePublisher,\n\t\t\t\tTaskEventProperties properties) {\n\t\t\treturn new EventEmittingItemProcessListener(messagePublisher,\n\t\t\t\t\tthis.taskEventProperties.getItemProcessOrder(), properties);\n\t\t}\n\n\t\t// @checkstyle:off\n\t\t@Bean\n\t\t@ConditionalOnProperty(prefix = \"spring.cloud.task.batch.events.skip\", name = \"enabled\", havingValue = \"true\",\n\t\t\t\tmatchIfMissing = true)\n\t\t// @checkstyle:on\n\t\tpublic SkipListener skipEventsListener(MessagePublisher messagePublisher, TaskEventProperties properties) {\n\t\t\treturn new EventEmittingSkipListener(messagePublisher, this.taskEventProperties.getItemProcessOrder(),\n\t\t\t\t\tproperties);\n\t\t}\n\n\t\t@Bean\n\t\tpublic MessagePublisher messagePublisher(StreamBridge streamBridge) {\n\t\t\treturn new MessagePublisher(streamBridge);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/EventEmittingChunkListener.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.springframework.batch.core.listener.ChunkListener;\nimport org.springframework.batch.infrastructure.item.Chunk;\nimport org.springframework.cloud.task.batch.listener.support.MessagePublisher;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * Provides informational messages around the {@link Chunk} of a batch job.\n *\n * The {@link ChunkListener#beforeChunk(Chunk)} and\n * {@link ChunkListener#afterChunk(Chunk)} are both no-ops in this implementation.\n * {@link ChunkListener#onChunkError(Exception,Chunk)}.\n *\n * @author Ali Shahbour\n */\npublic class EventEmittingChunkListener implements ChunkListener, Ordered {\n\n\tprivate int order = Ordered.LOWEST_PRECEDENCE;\n\n\tprivate MessagePublisher messagePublisher;\n\n\tprivate TaskEventProperties properties;\n\n\tpublic EventEmittingChunkListener(MessagePublisher messagePublisher, TaskEventProperties properties) {\n\t\tAssert.notNull(messagePublisher, \"messagePublisher is required\");\n\t\tAssert.notNull(properties, \"properties is required\");\n\t\tthis.messagePublisher = messagePublisher;\n\t\tthis.properties = properties;\n\t}\n\n\tpublic EventEmittingChunkListener(MessagePublisher messagePublisher, int order, TaskEventProperties properties) {\n\t\tthis(messagePublisher, properties);\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic void beforeChunk(Chunk chunk) {\n\t\tthis.messagePublisher.publish(this.properties.getChunkEventBindingName(), \"Before Chunk Processing\");\n\t}\n\n\t@Override\n\tpublic void afterChunk(Chunk chunk) {\n\t\tthis.messagePublisher.publish(this.properties.getChunkEventBindingName(), \"After Chunk Processing\");\n\t}\n\n\t@Override\n\tpublic void onChunkError(Exception exception, Chunk chunk) {\n\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/EventEmittingItemProcessListener.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.core.listener.ItemProcessListener;\nimport org.springframework.batch.infrastructure.item.ItemProcessor;\nimport org.springframework.cloud.task.batch.listener.support.BatchJobHeaders;\nimport org.springframework.cloud.task.batch.listener.support.MessagePublisher;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * Provides informational messages around the {@link ItemProcessListener} of a batch job.\n *\n * The {@link ItemProcessListener#beforeProcess(Object)} of this listener is a no-op.\n * {@link ItemProcessListener#afterProcess(Object, Object)} returns a message if an item\n * was filtered ({@link ItemProcessor} returned null), if the result of the processor was\n * equal to the input (via <code>.equals</code>), or if they were not equal.\n * {@link ItemProcessListener#onProcessError(Object, Exception)} provides the exception\n * via the {@link BatchJobHeaders#BATCH_EXCEPTION} message header.\n *\n * @author Michael Minella\n * @author Glenn Renfro\n * @author Ali Shahbour\n */\npublic class EventEmittingItemProcessListener implements ItemProcessListener, Ordered {\n\n\tprivate static final Log logger = LogFactory.getLog(EventEmittingItemProcessListener.class);\n\n\tprivate MessagePublisher messagePublisher;\n\n\tprivate int order = Ordered.LOWEST_PRECEDENCE;\n\n\tprivate TaskEventProperties properties;\n\n\tpublic EventEmittingItemProcessListener(MessagePublisher messagePublisher, TaskEventProperties properties) {\n\t\tAssert.notNull(messagePublisher, \"messagePublisher is required\");\n\t\tAssert.notNull(properties, \"properties is required\");\n\t\tthis.messagePublisher = messagePublisher;\n\t\tthis.properties = properties;\n\t}\n\n\tpublic EventEmittingItemProcessListener(MessagePublisher messagePublisher, int order,\n\t\t\tTaskEventProperties properties) {\n\t\tthis(messagePublisher, properties);\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic void beforeProcess(Object item) {\n\t}\n\n\t@Override\n\tpublic void afterProcess(Object item, Object result) {\n\t\tif (result == null) {\n\t\t\tthis.messagePublisher.publish(this.properties.getItemProcessEventBindingName(), \"1 item was filtered\");\n\t\t}\n\t\telse if (item.equals(result)) {\n\t\t\tthis.messagePublisher.publish(this.properties.getItemProcessEventBindingName(),\n\t\t\t\t\t\"item equaled result after processing\");\n\t\t}\n\t\telse {\n\t\t\tthis.messagePublisher.publish(this.properties.getItemProcessEventBindingName(),\n\t\t\t\t\t\"item did not equal result after processing\");\n\t\t}\n\t}\n\n\t@Override\n\tpublic void onProcessError(Object item, Exception e) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Executing onProcessError: \" + e.getMessage(), e);\n\t\t}\n\t\tthis.messagePublisher.publishWithThrowableHeader(this.properties.getItemProcessEventBindingName(),\n\t\t\t\t\"Exception while item was being processed\", e.getMessage());\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/EventEmittingItemReadListener.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.core.listener.ItemReadListener;\nimport org.springframework.batch.infrastructure.item.ItemReader;\nimport org.springframework.cloud.task.batch.listener.support.BatchJobHeaders;\nimport org.springframework.cloud.task.batch.listener.support.MessagePublisher;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * Provides informational messages around the {@link ItemReader} of a batch job.\n *\n * The {@link ItemReadListener#beforeRead()} and\n * {@link ItemReadListener#afterRead(Object)} are both no-ops in this implementation.\n * {@link ItemReadListener#onReadError(Exception)} provides the exception via the\n * {@link BatchJobHeaders#BATCH_EXCEPTION} message header.\n *\n * @author Glenn Renfro\n * @author Ali Shahbour\n */\npublic class EventEmittingItemReadListener implements ItemReadListener, Ordered {\n\n\tprivate static final Log logger = LogFactory.getLog(EventEmittingItemReadListener.class);\n\n\tprivate int order = Ordered.LOWEST_PRECEDENCE;\n\n\tprivate final MessagePublisher<String> messagePublisher;\n\n\tprivate TaskEventProperties properties;\n\n\tpublic EventEmittingItemReadListener(MessagePublisher messagePublisher, TaskEventProperties properties) {\n\t\tAssert.notNull(messagePublisher, \"messagePublisher is required\");\n\t\tAssert.notNull(properties, \"properties is required\");\n\t\tthis.properties = properties;\n\t\tthis.messagePublisher = messagePublisher;\n\t}\n\n\tpublic EventEmittingItemReadListener(MessagePublisher messagePublisher, int order, TaskEventProperties properties) {\n\t\tthis(messagePublisher, properties);\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic void beforeRead() {\n\n\t}\n\n\t@Override\n\tpublic void afterRead(Object item) {\n\n\t}\n\n\t@Override\n\tpublic void onReadError(Exception ex) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Executing onReadError: \" + ex.getMessage(), ex);\n\t\t}\n\n\t\tthis.messagePublisher.publishWithThrowableHeader(this.properties.getItemReadEventBindingName(),\n\t\t\t\t\"Exception while item was being read\", ex.getMessage());\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/EventEmittingItemWriteListener.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.core.listener.ItemWriteListener;\nimport org.springframework.batch.infrastructure.item.Chunk;\nimport org.springframework.cloud.task.batch.listener.support.BatchJobHeaders;\nimport org.springframework.cloud.task.batch.listener.support.MessagePublisher;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * Setups up the ItemWriteEventsListener to emit events to the spring cloud stream output\n * channel.\n *\n * Each method provides an informational message.\n * {@link ItemWriteListener#onWriteError(Exception, Chunk)} provides a message as well as\n * the exception's message via the {@link BatchJobHeaders#BATCH_EXCEPTION} message header.\n *\n * @author Glenn Renfro\n * @author Ali Shahbour\n */\npublic class EventEmittingItemWriteListener implements ItemWriteListener, Ordered {\n\n\tprivate static final Log logger = LogFactory.getLog(EventEmittingItemWriteListener.class);\n\n\tprivate int order = Ordered.LOWEST_PRECEDENCE;\n\n\tprivate final MessagePublisher<String> messagePublisher;\n\n\tprivate TaskEventProperties properties;\n\n\tpublic EventEmittingItemWriteListener(MessagePublisher messagePublisher, TaskEventProperties properties) {\n\t\tAssert.notNull(messagePublisher, \"messagePublisher is required\");\n\t\tAssert.notNull(properties, \"properties is required\");\n\n\t\tthis.messagePublisher = messagePublisher;\n\t\tthis.properties = properties;\n\t}\n\n\tpublic EventEmittingItemWriteListener(MessagePublisher messagePublisher, int order,\n\t\t\tTaskEventProperties properties) {\n\t\tthis(messagePublisher, properties);\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic void beforeWrite(Chunk items) {\n\t\tthis.messagePublisher.publish(this.properties.getItemWriteEventBindingName(),\n\t\t\t\titems.size() + \" items to be written.\");\n\t}\n\n\t@Override\n\tpublic void afterWrite(Chunk items) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Executing afterWrite: \" + items);\n\t\t}\n\t\tthis.messagePublisher.publish(this.properties.getItemWriteEventBindingName(),\n\t\t\t\titems.size() + \" items have been written.\");\n\t}\n\n\t@Override\n\tpublic void onWriteError(Exception exception, Chunk items) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Executing onWriteError: \" + exception.getMessage(), exception);\n\t\t}\n\t\tString payload = \"Exception while \" + items.size() + \" items are attempted to be written.\";\n\t\tthis.messagePublisher.publishWithThrowableHeader(this.properties.getItemWriteEventBindingName(), payload,\n\t\t\t\texception.getMessage());\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/EventEmittingJobExecutionListener.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.listener.JobExecutionListener;\nimport org.springframework.cloud.task.batch.listener.support.JobExecutionEvent;\nimport org.springframework.cloud.task.batch.listener.support.MessagePublisher;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * Provides {@link JobExecutionEvent} at both the start and end of the job's execution.\n *\n * @author Michael Minella\n * @author Glenn Renfro\n * @author Ali Shahbour\n */\npublic class EventEmittingJobExecutionListener implements JobExecutionListener, Ordered {\n\n\tprivate int order = Ordered.LOWEST_PRECEDENCE;\n\n\tprivate final MessagePublisher<JobExecutionEvent> messagePublisher;\n\n\tprivate TaskEventProperties properties;\n\n\tpublic EventEmittingJobExecutionListener(MessagePublisher messagePublisher, TaskEventProperties properties) {\n\t\tAssert.notNull(messagePublisher, \"messagePublisher is required\");\n\t\tAssert.notNull(properties, \"properties is required\");\n\n\t\tthis.messagePublisher = messagePublisher;\n\t\tthis.properties = properties;\n\t}\n\n\tpublic EventEmittingJobExecutionListener(MessagePublisher messagePublisher, int order,\n\t\t\tTaskEventProperties properties) {\n\t\tthis(messagePublisher, properties);\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic void beforeJob(JobExecution jobExecution) {\n\t\tthis.messagePublisher.publish(properties.getJobExecutionEventBindingName(),\n\t\t\t\tnew JobExecutionEvent(jobExecution));\n\t}\n\n\t@Override\n\tpublic void afterJob(JobExecution jobExecution) {\n\t\tthis.messagePublisher.publish(properties.getJobExecutionEventBindingName(),\n\t\t\t\tnew JobExecutionEvent(jobExecution));\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/EventEmittingSkipListener.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\n\nimport org.springframework.batch.core.listener.SkipListener;\nimport org.springframework.cloud.task.batch.listener.support.BatchJobHeaders;\nimport org.springframework.cloud.task.batch.listener.support.MessagePublisher;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * Setups up the SkipProcessListener to emit events to the spring cloud stream output\n * channel.\n *\n * This listener emits the exception's message via the\n * {@link BatchJobHeaders#BATCH_EXCEPTION} message header for each method. For\n * {@link SkipListener#onSkipInProcess(Object, Throwable)} and\n * {@link SkipListener#onSkipInWrite(Object, Throwable)} the body of the message consists\n * of the item that caused the error.\n *\n * @author Glenn Renfro\n * @author Ali Shahbour\n */\npublic class EventEmittingSkipListener implements SkipListener, Ordered {\n\n\tprivate static final Log logger = LogFactory.getLog(EventEmittingSkipListener.class);\n\n\tprivate final MessagePublisher<Object> messagePublisher;\n\n\tprivate int order = Ordered.LOWEST_PRECEDENCE;\n\n\tprivate TaskEventProperties properties;\n\n\tpublic EventEmittingSkipListener(MessagePublisher messagePublisher, TaskEventProperties properties) {\n\t\tAssert.notNull(messagePublisher, \"messagePublisher is required\");\n\t\tAssert.notNull(properties, \"properties is required\");\n\n\t\tthis.messagePublisher = messagePublisher;\n\t\tthis.properties = properties;\n\t}\n\n\tpublic EventEmittingSkipListener(MessagePublisher messagePublisher, int order, TaskEventProperties properties) {\n\t\tthis(messagePublisher, properties);\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic void onSkipInRead(Throwable t) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Executing onSkipInRead: \" + t.getMessage(), t);\n\t\t}\n\t\tthis.messagePublisher.publishWithThrowableHeader(this.properties.getSkipEventBindingName(),\n\t\t\t\t\"Skipped when reading.\", t.getMessage());\n\t}\n\n\t@Override\n\tpublic void onSkipInWrite(Object item, Throwable t) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Executing onSkipInWrite: \" + t.getMessage(), t);\n\t\t}\n\t\tthis.messagePublisher.publishWithThrowableHeader(this.properties.getSkipEventBindingName(), item,\n\t\t\t\tt.getMessage());\n\t}\n\n\t@Override\n\tpublic void onSkipInProcess(Object item, Throwable t) {\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Executing onSkipInProcess: \" + t.getMessage(), t);\n\t\t}\n\t\tthis.messagePublisher.publishWithThrowableHeader(this.properties.getSkipEventBindingName(), item,\n\t\t\t\tt.getMessage());\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/EventEmittingStepExecutionListener.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.springframework.batch.core.ExitStatus;\nimport org.springframework.batch.core.listener.StepExecutionListener;\nimport org.springframework.batch.core.step.StepExecution;\nimport org.springframework.cloud.task.batch.listener.support.MessagePublisher;\nimport org.springframework.cloud.task.batch.listener.support.StepExecutionEvent;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.core.Ordered;\nimport org.springframework.util.Assert;\n\n/**\n * Provides a {@link StepExecutionEvent} at the start and end of each step indicating the\n * step's status. The {@link StepExecutionListener#afterStep(StepExecution)} returns the\n * {@link ExitStatus} of the inputted {@link StepExecution}.\n *\n * @author Michael Minella\n * @author Glenn Renfro\n * @author Ali Shahbour\n */\npublic class EventEmittingStepExecutionListener implements StepExecutionListener, Ordered {\n\n\tprivate final MessagePublisher<StepExecutionEvent> messagePublisher;\n\n\tprivate int order = Ordered.LOWEST_PRECEDENCE;\n\n\tprivate TaskEventProperties properties;\n\n\tpublic EventEmittingStepExecutionListener(MessagePublisher messagePublisher, TaskEventProperties properties) {\n\t\tAssert.notNull(messagePublisher, \"messagePublisher is required\");\n\t\tAssert.notNull(properties, \"properties is required\");\n\n\t\tthis.messagePublisher = messagePublisher;\n\t\tthis.properties = properties;\n\t}\n\n\tpublic EventEmittingStepExecutionListener(MessagePublisher messagePublisher, int order,\n\t\t\tTaskEventProperties properties) {\n\t\tthis(messagePublisher, properties);\n\t\tthis.order = order;\n\t}\n\n\t@Override\n\tpublic void beforeStep(StepExecution stepExecution) {\n\t\tthis.messagePublisher.publish(this.properties.getStepExecutionEventBindingName(),\n\t\t\t\tnew StepExecutionEvent(stepExecution));\n\t}\n\n\t@Override\n\tpublic ExitStatus afterStep(StepExecution stepExecution) {\n\t\tthis.messagePublisher.publish(this.properties.getStepExecutionEventBindingName(),\n\t\t\t\tnew StepExecutionEvent(stepExecution));\n\n\t\treturn stepExecution.getExitStatus();\n\t}\n\n\t@Override\n\tpublic int getOrder() {\n\t\treturn this.order;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Stream-based batch listener components for Spring Cloud Task.\n */\npackage org.springframework.cloud.task.batch.listener;\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/BatchJobHeaders.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\n/**\n * Headers definitions used by the batch job plugin.\n *\n * @author Gunnar Hillert\n * @since 1.0\n */\npublic final class BatchJobHeaders {\n\n\t/**\n\t * Name of the batch listener event type.\n\t */\n\tpublic static final String BATCH_LISTENER_EVENT_TYPE = \"batch_listener_event_type\";\n\n\t/**\n\t * Key of the batch exception message.\n\t */\n\tpublic static final String BATCH_EXCEPTION = \"batch_exception\";\n\n\tprivate BatchJobHeaders() {\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/ExitStatus.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport org.springframework.util.Assert;\n\n/**\n * ExitStatus DTO created so that {@link org.springframework.batch.core.ExitStatus} can be\n * serialized into Json without. having to add mixins to an ObjectMapper\n *\n * @author Glenn Renfro\n */\npublic class ExitStatus {\n\n\tprivate String exitCode;\n\n\tprivate String exitDescription;\n\n\tpublic ExitStatus() {\n\t}\n\n\tpublic ExitStatus(org.springframework.batch.core.ExitStatus exitStatus) {\n\t\tAssert.notNull(exitStatus, \"exitStatus must not be null.\");\n\n\t\tthis.exitCode = exitStatus.getExitCode();\n\t\tthis.exitDescription = exitStatus.getExitDescription();\n\t}\n\n\tpublic String getExitCode() {\n\t\treturn this.exitCode;\n\t}\n\n\tpublic void setExitCode(String exitCode) {\n\t\tthis.exitCode = exitCode;\n\t}\n\n\tpublic String getExitDescription() {\n\t\treturn this.exitDescription;\n\t}\n\n\tpublic void setExitDescription(String exitDescription) {\n\t\tthis.exitDescription = exitDescription;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/JobExecutionEvent.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport java.time.LocalDateTime;\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.CopyOnWriteArrayList;\n\nimport org.springframework.batch.core.BatchStatus;\nimport org.springframework.batch.core.Entity;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.step.StepExecution;\nimport org.springframework.batch.infrastructure.item.ExecutionContext;\n\n/**\n * This is a JobEvent DTO created so that a {@link JobExecution} can be serialized into\n * Json without having to add mixins to an ObjectMapper.\n *\n * @author Glenn Renfro\n */\npublic class JobExecutionEvent extends Entity {\n\n\tprivate JobParametersEvent jobParameters;\n\n\tprivate JobInstanceEvent jobInstance;\n\n\tprivate Collection<StepExecutionEvent> stepExecutions = Collections.synchronizedList(new ArrayList<>());\n\n\tprivate BatchStatus status = BatchStatus.STARTING;\n\n\tprivate LocalDateTime startTime = null;\n\n\tprivate LocalDateTime createTime = LocalDateTime.now();\n\n\tprivate LocalDateTime endTime = null;\n\n\tprivate LocalDateTime lastUpdated = null;\n\n\tprivate ExitStatus exitStatus = new ExitStatus(new org.springframework.batch.core.ExitStatus(\"UNKNOWN\"));\n\n\tprivate ExecutionContext executionContext = new ExecutionContext();\n\n\tprivate List<Throwable> failureExceptions = new CopyOnWriteArrayList<>();\n\n\tpublic JobExecutionEvent() {\n\t\tsuper(0);\n\t}\n\n\t/**\n\t * Constructor for the StepExecution to initialize the DTO.\n\t * @param original the StepExecution to build this DTO around.\n\t */\n\tpublic JobExecutionEvent(JobExecution original) {\n\t\tsuper(original.getId());\n\t\tthis.jobParameters = new JobParametersEvent(original.getJobParameters().parameters());\n\t\tthis.jobInstance = new JobInstanceEvent(original.getJobInstance().getId(),\n\t\t\t\toriginal.getJobInstance().getJobName());\n\t\tfor (StepExecution stepExecution : original.getStepExecutions()) {\n\t\t\tthis.stepExecutions.add(new StepExecutionEvent(stepExecution));\n\t\t}\n\t\tthis.status = original.getStatus();\n\t\tthis.startTime = original.getStartTime();\n\t\tthis.createTime = original.getCreateTime();\n\t\tthis.endTime = original.getEndTime();\n\t\tthis.lastUpdated = original.getLastUpdated();\n\t\tthis.exitStatus = new ExitStatus(original.getExitStatus());\n\t\tthis.executionContext = original.getExecutionContext();\n\t\tthis.failureExceptions = original.getFailureExceptions();\n\t\tthis.setVersion(original.getVersion());\n\t}\n\n\tpublic JobParametersEvent getJobParameters() {\n\t\treturn this.jobParameters;\n\t}\n\n\tpublic LocalDateTime getEndTime() {\n\t\treturn this.endTime;\n\t}\n\n\tpublic void setEndTime(LocalDateTime endTime) {\n\t\tthis.endTime = endTime;\n\t}\n\n\tpublic LocalDateTime getStartTime() {\n\t\treturn this.startTime;\n\t}\n\n\tpublic void setStartTime(LocalDateTime startTime) {\n\t\tthis.startTime = startTime;\n\t}\n\n\tpublic BatchStatus getStatus() {\n\t\treturn this.status;\n\t}\n\n\t/**\n\t * Set the value of the status field.\n\t * @param status the status to set\n\t */\n\tpublic void setStatus(BatchStatus status) {\n\t\tthis.status = status;\n\t}\n\n\t/**\n\t * Upgrade the status field if the provided value is greater than the existing one.\n\t * Clients using this method to set the status can be sure that they don't overwrite a\n\t * failed status with an successful one.\n\t * @param status the new status value\n\t */\n\tpublic void upgradeStatus(BatchStatus status) {\n\t\tthis.status = this.status.upgradeTo(status);\n\t}\n\n\t/**\n\t * Convenience getter for the id of the enclosing job. Useful for DAO implementations.\n\t * @return the id of the enclosing job\n\t */\n\tpublic Long getJobId() {\n\t\tif (this.jobInstance != null) {\n\t\t\treturn this.jobInstance.getId();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * @return the exitCode for the job.\n\t */\n\tpublic ExitStatus getExitStatus() {\n\t\treturn this.exitStatus;\n\t}\n\n\t/**\n\t * @param exitStatus the exit status for the job.\n\t */\n\tpublic void setExitStatus(ExitStatus exitStatus) {\n\t\tthis.exitStatus = exitStatus;\n\t}\n\n\t/**\n\t * @return the Job that is executing.\n\t */\n\tpublic JobInstanceEvent getJobInstance() {\n\t\treturn this.jobInstance;\n\t}\n\n\tpublic void setJobInstance(JobInstanceEvent jobInstance) {\n\t\tthis.jobInstance = jobInstance;\n\t}\n\n\t/**\n\t * Accessor for the step executions.\n\t * @return the step executions that were registered\n\t */\n\tpublic Collection<StepExecutionEvent> getStepExecutions() {\n\t\treturn Collections.unmodifiableList(new ArrayList<>(this.stepExecutions));\n\t}\n\n\t/**\n\t * Returns the {@link ExecutionContext} for this execution. The content is expected to\n\t * be persisted after each step completion (successful or not).\n\t * @return the context\n\t */\n\tpublic ExecutionContext getExecutionContext() {\n\t\treturn this.executionContext;\n\t}\n\n\t/**\n\t * Sets the {@link ExecutionContext} for this execution.\n\t * @param executionContext the context\n\t */\n\tpublic void setExecutionContext(ExecutionContext executionContext) {\n\t\tthis.executionContext = executionContext;\n\t}\n\n\t/**\n\t * @return the time when this execution was created.\n\t */\n\tpublic LocalDateTime getCreateTime() {\n\t\treturn this.createTime;\n\t}\n\n\t/**\n\t * @param createTime creation time of this execution.\n\t */\n\tpublic void setCreateTime(LocalDateTime createTime) {\n\t\tthis.createTime = createTime;\n\t}\n\n\t/**\n\t * Get the date representing the last time this JobExecution was updated in the\n\t * JobRepository.\n\t * @return Date representing the last time this JobExecution was updated.\n\t */\n\tpublic LocalDateTime getLastUpdated() {\n\t\treturn this.lastUpdated;\n\t}\n\n\t/**\n\t * Set the last time this {@link JobExecution} was updated.\n\t * @param lastUpdated The date the {@link JobExecution} was updated.\n\t */\n\tpublic void setLastUpdated(LocalDateTime lastUpdated) {\n\t\tthis.lastUpdated = lastUpdated;\n\t}\n\n\tpublic List<Throwable> getFailureExceptions() {\n\t\treturn this.failureExceptions;\n\t}\n\n\t/**\n\t * Add the provided throwable to the failure exception list.\n\t * @param t a {@link Throwable} to be added to the exception list.\n\t */\n\tpublic synchronized void addFailureException(Throwable t) {\n\t\tthis.failureExceptions.add(t);\n\t}\n\n\t/**\n\t * Return all failure causing exceptions for this JobExecution, including step\n\t * executions.\n\t * @return List&lt;Throwable&gt; containing all exceptions causing failure for this\n\t * JobExecution.\n\t */\n\tpublic synchronized List<Throwable> getAllFailureExceptions() {\n\n\t\tSet<Throwable> allExceptions = new HashSet<>(this.failureExceptions);\n\t\tfor (StepExecutionEvent stepExecution : this.stepExecutions) {\n\t\t\tallExceptions.addAll(stepExecution.getFailureExceptions());\n\t\t}\n\n\t\treturn new ArrayList<>(allExceptions);\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t *\n\t * @see org.springframework.batch.core.domain.Entity#toString()\n\t */\n\t@Override\n\tpublic String toString() {\n\t\treturn super.toString() + String.format(\n\t\t\t\t\", startTime=%s, endTime=%s, lastUpdated=%s, status=%s, exitStatus=%s, job=[%s], jobParameters=[%s]\",\n\t\t\t\tthis.startTime, this.endTime, this.lastUpdated, this.status, this.exitStatus, this.jobInstance,\n\t\t\t\tthis.jobParameters);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/JobInstanceEvent.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport org.springframework.batch.core.Entity;\nimport org.springframework.util.Assert;\n\n/**\n * This is a JobInstance DTO created so that a\n * {@link org.springframework.batch.core.job.JobInstance} can be serialized into Json\n * without having to add mixins to an ObjectMapper.\n *\n * @author Glenn Renfro\n */\n\npublic class JobInstanceEvent extends Entity {\n\n\tprivate String jobName;\n\n\tpublic JobInstanceEvent() {\n\t\tsuper(-1L);\n\t}\n\n\tpublic JobInstanceEvent(Long id, String jobName) {\n\t\tsuper(id);\n\t\tAssert.hasLength(jobName, \"jobName must have length greater than zero.\");\n\t\tthis.jobName = jobName;\n\t}\n\n\t/**\n\t * @return the job name. (Equivalent to getJob().getName())\n\t */\n\tpublic String getJobName() {\n\t\treturn this.jobName;\n\t}\n\n\tpublic String toString() {\n\t\treturn super.toString() + \", Job=[\" + this.jobName + \"]\";\n\t}\n\n\tpublic long getInstanceId() {\n\t\treturn super.getId();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/JobParameterEvent.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport java.util.Date;\nimport java.util.Objects;\n\nimport org.springframework.batch.core.job.parameters.JobParameter;\n\n/**\n * This is a JobParameter DTO created so that a\n * {@link org.springframework.batch.core.job.parameters.JobParameter} can be serialized\n * into Json without having to add mixins to an ObjectMapper.\n *\n * @author Glenn Renfro\n */\npublic class JobParameterEvent {\n\n\tprivate Object parameter;\n\n\tprivate boolean identifying;\n\n\tpublic JobParameterEvent() {\n\t}\n\n\tpublic JobParameterEvent(JobParameter jobParameter) {\n\t\tthis.parameter = jobParameter.value();\n\t\tthis.identifying = jobParameter.identifying();\n\t}\n\n\tpublic boolean isIdentifying() {\n\t\treturn this.identifying;\n\t}\n\n\t/**\n\t * @return the value contained within this JobParameter.\n\t */\n\tpublic Object getValue() {\n\n\t\tif (this.parameter != null && this.parameter.getClass().isInstance(Date.class)) {\n\t\t\treturn new Date(((Date) this.parameter).getTime());\n\t\t}\n\t\telse {\n\t\t\treturn this.parameter;\n\t\t}\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (!(obj instanceof JobParameterEvent)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this == obj) {\n\t\t\treturn true;\n\t\t}\n\n\t\tJobParameterEvent rhs = (JobParameterEvent) obj;\n\t\treturn Objects.equals(this.parameter, rhs.parameter);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.parameter == null ? null : this.parameter.toString();\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int BASE_HASH = 7;\n\t\tfinal int MULTIPLIER_HASH = 21;\n\t\treturn BASE_HASH + MULTIPLIER_HASH * this.parameter.hashCode();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/JobParametersEvent.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.springframework.batch.core.job.parameters.JobParameter;\n\n/**\n * This is a JobParametersEvent DTO created so that a\n * {@link org.springframework.batch.core.job.parameters.JobParameters} can be serialized\n * into Json without having to add mixins to an ObjectMapper.\n *\n * @author Glenn Renfro\n */\npublic class JobParametersEvent {\n\n\tprivate final Set<JobParameterEvent> parameters;\n\n\tpublic JobParametersEvent() {\n\t\tthis.parameters = new HashSet<>();\n\t}\n\n\tpublic JobParametersEvent(Set<JobParameter<?>> jobParameters) {\n\t\tthis.parameters = new HashSet<>();\n\t\tfor (JobParameter<?> entry : jobParameters) {\n\t\t\tthis.parameters.add(new JobParameterEvent(entry));\n\t\t}\n\t}\n\n\t/**\n\t * Get a map of all parameters, including string, long, and date.\n\t * @return an unmodifiable map containing all parameters.\n\t */\n\tpublic Set<JobParameterEvent> getParameters() {\n\t\treturn new HashSet<>(this.parameters);\n\t}\n\n\t/**\n\t * @return true if the parameters is empty, false otherwise.\n\t */\n\tpublic boolean isEmpty() {\n\t\treturn this.parameters.isEmpty();\n\t}\n\n\t@Override\n\tpublic boolean equals(Object obj) {\n\t\tif (!(obj instanceof JobParametersEvent)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (obj == this) {\n\t\t\treturn true;\n\t\t}\n\n\t\tJobParametersEvent rhs = (JobParametersEvent) obj;\n\t\treturn this.parameters.equals(rhs.parameters);\n\t}\n\n\t@Override\n\tpublic int hashCode() {\n\t\tfinal int BASE_HASH = 17;\n\t\tfinal int MULTIPLIER_HASH = 23;\n\t\treturn BASE_HASH + MULTIPLIER_HASH * this.parameters.hashCode();\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn this.parameters.toString();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/MessagePublisher.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport org.springframework.cloud.stream.function.StreamBridge;\nimport org.springframework.messaging.Message;\nimport org.springframework.messaging.support.MessageBuilder;\nimport org.springframework.util.Assert;\n\n/**\n * Utility class that sends batch job listener payloads to the notification channel.\n *\n * @param <P> payload type\n * @author Glenn Renfro\n */\npublic class MessagePublisher<P> {\n\n\tprivate final StreamBridge streamBridge;\n\n\tpublic MessagePublisher(StreamBridge streamBridge) {\n\t\tAssert.notNull(streamBridge, \"streamBridge must not be null\");\n\t\tthis.streamBridge = streamBridge;\n\t}\n\n\tpublic final void publish(String bindingName, P payload) {\n\t\tif (payload instanceof Message) {\n\t\t\tthis.publishMessage(bindingName, (Message<?>) payload);\n\t\t}\n\t\telse {\n\t\t\tMessage<P> message = MessageBuilder.withPayload(payload).build();\n\t\t\tthis.streamBridge.send(bindingName, message);\n\t\t}\n\t}\n\n\tprivate void publishMessage(String bindingName, Message<?> message) {\n\t\tthis.streamBridge.send(bindingName, message);\n\t}\n\n\tpublic void publishWithThrowableHeader(String bindingName, P payload, String header) {\n\t\tMessage<P> message = MessageBuilder.withPayload(payload)\n\t\t\t.setHeader(BatchJobHeaders.BATCH_EXCEPTION, header)\n\t\t\t.build();\n\t\tpublishMessage(bindingName, message);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/StepExecutionEvent.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport java.time.LocalDateTime;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.springframework.batch.core.BatchStatus;\nimport org.springframework.batch.core.Entity;\nimport org.springframework.batch.core.step.StepExecution;\nimport org.springframework.batch.infrastructure.item.ExecutionContext;\nimport org.springframework.util.Assert;\n\n/**\n * This is a StepExecution DTO created so that a\n * {@link org.springframework.batch.core.step.StepExecution} can be serialized into Json\n * without having to add mixins to an ObjectMapper.\n *\n * @author Glenn Renfro\n */\npublic class StepExecutionEvent extends Entity {\n\n\tprivate long jobExecutionId;\n\n\tprivate String stepName;\n\n\tprivate BatchStatus status = BatchStatus.STARTING;\n\n\tprivate long readCount = 0;\n\n\tprivate long writeCount = 0;\n\n\tprivate long commitCount = 0;\n\n\tprivate long rollbackCount = 0;\n\n\tprivate long readSkipCount = 0;\n\n\tprivate long processSkipCount = 0;\n\n\tprivate long writeSkipCount = 0;\n\n\tprivate LocalDateTime startTime = LocalDateTime.now();\n\n\tprivate LocalDateTime endTime = null;\n\n\tprivate LocalDateTime lastUpdated = null;\n\n\tprivate ExecutionContext executionContext = new ExecutionContext();\n\n\tprivate ExitStatus exitStatus = new ExitStatus(org.springframework.batch.core.ExitStatus.EXECUTING);\n\n\tprivate boolean terminateOnly;\n\n\tprivate long filterCount;\n\n\tprivate List<Throwable> failureExceptions = new CopyOnWriteArrayList<>();\n\n\tpublic StepExecutionEvent() {\n\t\tsuper(0);\n\t}\n\n\t/**\n\t * Constructor for the StepExecution to initialize the DTO.\n\t * @param stepExecution the StepExecution to build this DTO around.\n\t */\n\tpublic StepExecutionEvent(StepExecution stepExecution) {\n\t\tsuper(stepExecution.getJobExecutionId());\n\t\tAssert.notNull(stepExecution, \"StepExecution must be provided to re-hydrate an existing StepExecutionEvent\");\n\t\tAssert.notNull(stepExecution.getJobExecution(),\n\t\t\t\t\"JobExecution must be provided to re-hydrate an existing StepExecutionEvent\");\n\t\tthis.jobExecutionId = stepExecution.getJobExecutionId();\n\t\tthis.stepName = stepExecution.getStepName();\n\n\t\tthis.status = stepExecution.getStatus();\n\t\tthis.exitStatus = new ExitStatus(stepExecution.getExitStatus());\n\t\tthis.executionContext = stepExecution.getExecutionContext();\n\t\tfor (Throwable throwable : stepExecution.getFailureExceptions()) {\n\t\t\tthis.failureExceptions.add(throwable);\n\t\t}\n\t\tthis.terminateOnly = stepExecution.isTerminateOnly();\n\n\t\tthis.endTime = stepExecution.getEndTime();\n\t\tthis.lastUpdated = stepExecution.getLastUpdated();\n\t\tthis.startTime = stepExecution.getStartTime();\n\n\t\tthis.commitCount = stepExecution.getCommitCount();\n\t\tthis.filterCount = stepExecution.getFilterCount();\n\t\tthis.processSkipCount = stepExecution.getProcessSkipCount();\n\t\tthis.readCount = stepExecution.getReadCount();\n\t\tthis.readSkipCount = stepExecution.getReadSkipCount();\n\t\tthis.rollbackCount = stepExecution.getRollbackCount();\n\t\tthis.writeCount = stepExecution.getWriteCount();\n\t\tthis.writeSkipCount = stepExecution.getWriteSkipCount();\n\t}\n\n\t/**\n\t * Returns the {@link ExecutionContext} for this execution.\n\t * @return the attributes\n\t */\n\tpublic ExecutionContext getExecutionContext() {\n\t\treturn this.executionContext;\n\t}\n\n\t/**\n\t * Sets the {@link ExecutionContext} for this execution.\n\t * @param executionContext the attributes\n\t */\n\tpublic void setExecutionContext(ExecutionContext executionContext) {\n\t\tthis.executionContext = executionContext;\n\t}\n\n\t/**\n\t * Returns the current number of commits for this execution.\n\t * @return the current number of commits\n\t */\n\tpublic long getCommitCount() {\n\t\treturn this.commitCount;\n\t}\n\n\t/**\n\t * Sets the current number of commits for this execution.\n\t * @param commitCount the current number of commits\n\t */\n\tpublic void setCommitCount(int commitCount) {\n\t\tthis.commitCount = commitCount;\n\t}\n\n\t/**\n\t * Returns the time that this execution ended.\n\t * @return the time that this execution ended\n\t */\n\tpublic LocalDateTime getEndTime() {\n\t\treturn this.endTime;\n\t}\n\n\t/**\n\t * Sets the time that this execution ended.\n\t * @param endTime the time that this execution ended\n\t */\n\tpublic void setEndTime(LocalDateTime endTime) {\n\t\tthis.endTime = endTime;\n\t}\n\n\t/**\n\t * Returns the current number of items read for this execution.\n\t * @return the current number of items read for this execution\n\t */\n\tpublic long getReadCount() {\n\t\treturn this.readCount;\n\t}\n\n\t/**\n\t * Sets the current number of read items for this execution.\n\t * @param readCount the current number of read items for this execution\n\t */\n\tpublic void setReadCount(int readCount) {\n\t\tthis.readCount = readCount;\n\t}\n\n\t/**\n\t * Returns the current number of items written for this execution.\n\t * @return the current number of items written for this execution\n\t */\n\tpublic long getWriteCount() {\n\t\treturn this.writeCount;\n\t}\n\n\t/**\n\t * Sets the current number of written items for this execution.\n\t * @param writeCount the current number of written items for this execution\n\t */\n\tpublic void setWriteCount(int writeCount) {\n\t\tthis.writeCount = writeCount;\n\t}\n\n\t/**\n\t * Returns the current number of rollbacks for this execution.\n\t * @return the current number of rollbacks for this execution\n\t */\n\tpublic long getRollbackCount() {\n\t\treturn this.rollbackCount;\n\t}\n\n\t/**\n\t * Setter for number of rollbacks for this execution.\n\t * @param rollbackCount the number of rollbacks for this execution\n\t */\n\tpublic void setRollbackCount(int rollbackCount) {\n\t\tthis.rollbackCount = rollbackCount;\n\t}\n\n\t/**\n\t * Returns the current number of items filtered out of this execution.\n\t * @return the current number of items filtered out of this execution\n\t */\n\tpublic long getFilterCount() {\n\t\treturn this.filterCount;\n\t}\n\n\t/**\n\t * Public setter for the number of items filtered out of this execution.\n\t * @param filterCount the number of items filtered out of this execution to set\n\t */\n\tpublic void setFilterCount(int filterCount) {\n\t\tthis.filterCount = filterCount;\n\t}\n\n\t/**\n\t * Gets the time this execution started.\n\t * @return the time this execution started\n\t */\n\tpublic LocalDateTime getStartTime() {\n\t\treturn this.startTime;\n\t}\n\n\t/**\n\t * Sets the time this execution started.\n\t * @param startTime the time this execution started\n\t */\n\tpublic void setStartTime(LocalDateTime startTime) {\n\t\tthis.startTime = startTime;\n\t}\n\n\t/**\n\t * Returns the current status of this step.\n\t * @return the current status of this step\n\t */\n\tpublic BatchStatus getStatus() {\n\t\treturn this.status;\n\t}\n\n\t/**\n\t * Sets the current status of this step.\n\t * @param status the current status of this step\n\t */\n\tpublic void setStatus(BatchStatus status) {\n\t\tthis.status = status;\n\t}\n\n\t/**\n\t * @return the name of the step.\n\t */\n\tpublic String getStepName() {\n\t\treturn this.stepName;\n\t}\n\n\tpublic void setStepName(String stepName) {\n\t\tthis.stepName = stepName;\n\t}\n\n\t/**\n\t * @return the exitCode\n\t */\n\tpublic ExitStatus getExitStatus() {\n\t\treturn this.exitStatus;\n\t}\n\n\t/**\n\t * @param exitStatus the {@link ExitStatus} for the step.\n\t */\n\tpublic void setExitStatus(ExitStatus exitStatus) {\n\t\tthis.exitStatus = exitStatus;\n\t}\n\n\t/**\n\t * @return flag to indicate that an execution should halt\n\t */\n\tpublic boolean isTerminateOnly() {\n\t\treturn this.terminateOnly;\n\t}\n\n\t/**\n\t * Set a flag that will signal to an execution environment that this execution (and\n\t * its surrounding job) wishes to exit.\n\t */\n\tpublic void setTerminateOnly() {\n\t\tthis.terminateOnly = true;\n\t}\n\n\t/**\n\t * @return the total number of items skipped.\n\t */\n\tpublic long getSkipCount() {\n\t\treturn this.readSkipCount + this.processSkipCount + this.writeSkipCount;\n\t}\n\n\t/**\n\t * Increment the number of commits.\n\t */\n\tpublic void incrementCommitCount() {\n\t\tthis.commitCount++;\n\t}\n\n\t/**\n\t * @return the number of records skipped on read.\n\t */\n\tpublic long getReadSkipCount() {\n\t\treturn this.readSkipCount;\n\t}\n\n\t/**\n\t * Set the number of records skipped on read.\n\t * @param readSkipCount the number of records to be skipped on read.\n\t */\n\tpublic void setReadSkipCount(int readSkipCount) {\n\t\tthis.readSkipCount = readSkipCount;\n\t}\n\n\t/**\n\t * @return the number of records skipped on write\n\t */\n\tpublic long getWriteSkipCount() {\n\t\treturn this.writeSkipCount;\n\t}\n\n\t/**\n\t * Set the number of records skipped on write.\n\t * @param writeSkipCount the number of records to be skipped on write.\n\t */\n\tpublic void setWriteSkipCount(int writeSkipCount) {\n\t\tthis.writeSkipCount = writeSkipCount;\n\t}\n\n\t/**\n\t * @return the number of records skipped during processing\n\t */\n\tpublic long getProcessSkipCount() {\n\t\treturn this.processSkipCount;\n\t}\n\n\t/**\n\t * Set the number of records skipped during processing.\n\t * @param processSkipCount the number of records skip during processing.\n\t */\n\tpublic void setProcessSkipCount(int processSkipCount) {\n\t\tthis.processSkipCount = processSkipCount;\n\t}\n\n\t/**\n\t * @return the Date representing the last time this execution was persisted.\n\t */\n\tpublic LocalDateTime getLastUpdated() {\n\t\treturn this.lastUpdated;\n\t}\n\n\t/**\n\t * Set the time when the StepExecution was last updated before persisting.\n\t * @param lastUpdated the {@link LocalDateTime} the StepExecution was last updated.\n\t */\n\tpublic void setLastUpdated(LocalDateTime lastUpdated) {\n\t\tthis.lastUpdated = lastUpdated;\n\t}\n\n\tpublic List<Throwable> getFailureExceptions() {\n\t\treturn this.failureExceptions;\n\t}\n\n\tpublic long getJobExecutionId() {\n\t\treturn this.jobExecutionId;\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t *\n\t * @see org.springframework.batch.container.common.domain.Entity#equals(java.\n\t * lang.Object)\n\t */\n\t@Override\n\tpublic boolean equals(Object obj) {\n\n\t\tif (!(obj instanceof StepExecution)) {\n\t\t\treturn super.equals(obj);\n\t\t}\n\t\tStepExecution other = (StepExecution) obj;\n\n\t\treturn this.stepName.equals(other.getStepName()) && (this.jobExecutionId == other.getJobExecutionId())\n\t\t\t\t&& getId() == other.getId();\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t *\n\t * @see org.springframework.batch.container.common.domain.Entity#hashCode()\n\t */\n\t@Override\n\tpublic int hashCode() {\n\t\tObject jobExecutionId = getJobExecutionId();\n\t\tLong id = getId();\n\t\treturn super.hashCode() + 31 * (this.stepName != null ? this.stepName.hashCode() : 0)\n\t\t\t\t+ 91 * (jobExecutionId != null ? jobExecutionId.hashCode() : 0) + 59 * (id != null ? id.hashCode() : 0);\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn String.format(getSummary() + \", exitDescription=%s\", this.exitStatus.getExitDescription());\n\t}\n\n\tpublic String getSummary() {\n\t\treturn super.toString() + String.format(\n\t\t\t\t\", name=%s, status=%s, exitStatus=%s, readCount=%d, \"\n\t\t\t\t\t\t+ \"filterCount=%d, writeCount=%d readSkipCount=%d, writeSkipCount=%d\"\n\t\t\t\t\t\t+ \", processSkipCount=%d, commitCount=%d, rollbackCount=%d\",\n\t\t\t\tthis.stepName, this.status, this.exitStatus.getExitCode(), this.readCount, this.filterCount,\n\t\t\t\tthis.writeCount, this.readSkipCount, this.writeSkipCount, this.processSkipCount, this.commitCount,\n\t\t\t\tthis.rollbackCount);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/TaskBatchEventListenerBeanPostProcessor.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport java.lang.reflect.Field;\n\nimport org.springframework.aot.hint.MemberCategory;\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.aot.hint.RuntimeHintsRegistrar;\nimport org.springframework.batch.core.job.AbstractJob;\nimport org.springframework.batch.core.listener.ChunkListener;\nimport org.springframework.batch.core.listener.ItemProcessListener;\nimport org.springframework.batch.core.listener.ItemReadListener;\nimport org.springframework.batch.core.listener.ItemWriteListener;\nimport org.springframework.batch.core.listener.JobExecutionListener;\nimport org.springframework.batch.core.listener.SkipListener;\nimport org.springframework.batch.core.listener.StepExecutionListener;\nimport org.springframework.batch.core.step.AbstractStep;\nimport org.springframework.batch.core.step.item.ChunkOrientedTasklet;\nimport org.springframework.batch.core.step.item.SimpleChunkProcessor;\nimport org.springframework.batch.core.step.item.SimpleChunkProvider;\nimport org.springframework.batch.core.step.tasklet.Tasklet;\nimport org.springframework.batch.core.step.tasklet.TaskletStep;\nimport org.springframework.beans.BeansException;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.config.BeanPostProcessor;\nimport org.springframework.cloud.task.batch.listener.BatchEventAutoConfiguration;\nimport org.springframework.cloud.task.batch.listener.support.TaskBatchEventListenerBeanPostProcessor.RuntimeHint;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.ImportRuntimeHints;\nimport org.springframework.util.ReflectionUtils;\n\n/**\n * Attaches the listeners to the job and its steps. Based on the type of bean that is\n * being processed will determine what listener is attached.\n * <ul>\n * <li>If the bean is of type AbstractJob then the JobExecutionListener is registered with\n * this bean.</li>\n * <li>If the bean is of type AbstractStep then the StepExecutionListener is registered\n * with this bean.</li>\n * <li>If the bean is of type TaskletStep then the ChunkEventListener is registered with\n * this bean.</li>\n * <li>If the tasklet for the TaskletStep is of type ChunkOrientedTasklet the following\n * listeners will be registered.</li>\n * <li>\n * <ul>\n * <li>ItemReadListener with the ChunkProvider.</li>\n * <li>ItemProcessListener with the ChunkProcessor.</li>\n * <li>ItemWriteEventsListener with the ChunkProcessor.</li>\n * <li>SkipEventsListener with the ChunkProcessor.</li>\n * </ul>\n * </li>\n * </ul>\n *\n * @author Michael Minella\n * @author Glenn Renfro\n */\n@ImportRuntimeHints(RuntimeHint.class)\npublic class TaskBatchEventListenerBeanPostProcessor implements BeanPostProcessor {\n\n\t@Autowired\n\tprivate ApplicationContext applicationContext;\n\n\t@Override\n\tpublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\n\n\t\tregisterJobExecutionEventListener(bean);\n\n\t\tif (bean instanceof AbstractStep) {\n\t\t\tregisterStepExecutionEventListener(bean);\n\t\t\tif (bean instanceof TaskletStep taskletStep) {\n\t\t\t\tTasklet tasklet = taskletStep.getTasklet();\n\t\t\t\tregisterChunkEventsListener(bean);\n\n\t\t\t\tif (tasklet instanceof ChunkOrientedTasklet) {\n\t\t\t\t\tField chunkProviderField = ReflectionUtils.findField(ChunkOrientedTasklet.class, \"chunkProvider\");\n\t\t\t\t\tReflectionUtils.makeAccessible(chunkProviderField);\n\t\t\t\t\tSimpleChunkProvider chunkProvider = (SimpleChunkProvider) ReflectionUtils\n\t\t\t\t\t\t.getField(chunkProviderField, tasklet);\n\t\t\t\t\tField chunkProcessorField = ReflectionUtils.findField(ChunkOrientedTasklet.class, \"chunkProcessor\");\n\t\t\t\t\tReflectionUtils.makeAccessible(chunkProcessorField);\n\t\t\t\t\tSimpleChunkProcessor chunkProcessor = (SimpleChunkProcessor) ReflectionUtils\n\t\t\t\t\t\t.getField(chunkProcessorField, tasklet);\n\t\t\t\t\tregisterItemReadEvents(chunkProvider);\n\t\t\t\t\tregisterSkipEvents(chunkProvider);\n\t\t\t\t\tregisterItemProcessEvents(chunkProcessor);\n\t\t\t\t\tregisterItemWriteEvents(chunkProcessor);\n\t\t\t\t\tregisterSkipEvents(chunkProcessor);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn bean;\n\t}\n\n\t@Override\n\tpublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n\t\treturn bean;\n\t}\n\n\tprivate void registerItemProcessEvents(SimpleChunkProcessor chunkProcessor) {\n\t\tif (this.applicationContext.containsBean(BatchEventAutoConfiguration.ITEM_PROCESS_EVENTS_LISTENER)) {\n\t\t\tchunkProcessor.registerListener((ItemProcessListener) this.applicationContext\n\t\t\t\t.getBean(BatchEventAutoConfiguration.ITEM_PROCESS_EVENTS_LISTENER));\n\t\t}\n\t}\n\n\tprivate void registerItemReadEvents(SimpleChunkProvider chunkProvider) {\n\t\tif (this.applicationContext.containsBean(BatchEventAutoConfiguration.ITEM_READ_EVENTS_LISTENER)) {\n\t\t\tchunkProvider.registerListener((ItemReadListener) this.applicationContext\n\t\t\t\t.getBean(BatchEventAutoConfiguration.ITEM_READ_EVENTS_LISTENER));\n\t\t}\n\t}\n\n\tprivate void registerItemWriteEvents(SimpleChunkProcessor chunkProcessor) {\n\t\tif (this.applicationContext.containsBean(BatchEventAutoConfiguration.ITEM_WRITE_EVENTS_LISTENER)) {\n\t\t\tchunkProcessor.registerListener((ItemWriteListener) this.applicationContext\n\t\t\t\t.getBean(BatchEventAutoConfiguration.ITEM_WRITE_EVENTS_LISTENER));\n\t\t}\n\t}\n\n\tprivate void registerSkipEvents(SimpleChunkProvider chunkProvider) {\n\t\tif (this.applicationContext.containsBean(BatchEventAutoConfiguration.SKIP_EVENTS_LISTENER)) {\n\t\t\tchunkProvider.registerListener(\n\t\t\t\t\t(SkipListener) this.applicationContext.getBean(BatchEventAutoConfiguration.SKIP_EVENTS_LISTENER));\n\t\t}\n\t}\n\n\tprivate void registerSkipEvents(SimpleChunkProcessor chunkProcessor) {\n\t\tif (this.applicationContext.containsBean(BatchEventAutoConfiguration.SKIP_EVENTS_LISTENER)) {\n\t\t\tchunkProcessor.registerListener(\n\t\t\t\t\t(SkipListener) this.applicationContext.getBean(BatchEventAutoConfiguration.SKIP_EVENTS_LISTENER));\n\t\t}\n\t}\n\n\tprivate void registerChunkEventsListener(Object bean) {\n\t\tif (this.applicationContext.containsBean(BatchEventAutoConfiguration.CHUNK_EVENTS_LISTENER)) {\n\t\t\t((TaskletStep) bean).registerChunkListener(\n\t\t\t\t\t(ChunkListener) this.applicationContext.getBean(BatchEventAutoConfiguration.CHUNK_EVENTS_LISTENER));\n\t\t}\n\t}\n\n\tprivate void registerJobExecutionEventListener(Object bean) {\n\t\tif (bean instanceof AbstractJob job\n\t\t\t\t&& this.applicationContext.containsBean(BatchEventAutoConfiguration.JOB_EXECUTION_EVENTS_LISTENER)) {\n\t\t\tJobExecutionListener jobExecutionEventsListener = (JobExecutionListener) this.applicationContext\n\t\t\t\t.getBean(BatchEventAutoConfiguration.JOB_EXECUTION_EVENTS_LISTENER);\n\n\t\t\tjob.registerJobExecutionListener(jobExecutionEventsListener);\n\t\t}\n\t}\n\n\tprivate void registerStepExecutionEventListener(Object bean) {\n\t\tif (this.applicationContext.containsBean(BatchEventAutoConfiguration.STEP_EXECUTION_EVENTS_LISTENER)) {\n\t\t\tStepExecutionListener stepExecutionListener = (StepExecutionListener) this.applicationContext\n\t\t\t\t.getBean(BatchEventAutoConfiguration.STEP_EXECUTION_EVENTS_LISTENER);\n\t\t\tAbstractStep step = (AbstractStep) bean;\n\t\t\tstep.registerStepExecutionListener(stepExecutionListener);\n\t\t}\n\t}\n\n\tstatic class RuntimeHint implements RuntimeHintsRegistrar {\n\n\t\t@Override\n\t\tpublic void registerHints(RuntimeHints hints, ClassLoader classLoader) {\n\t\t\thints.reflection().registerType(ChunkOrientedTasklet.class, MemberCategory.DECLARED_FIELDS);\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/TaskEventProperties.java",
    "content": "/*\n * Copyright 2017-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.core.Ordered;\n\n/**\n * @author Ali Shahbour\n */\n@ConfigurationProperties(prefix = \"spring.cloud.task.batch.events\")\npublic class TaskEventProperties {\n\n\t/**\n\t * Establishes the default {@link Ordered} precedence for\n\t * {@link org.springframework.batch.core.JobExecutionListener}.\n\t */\n\tprivate int jobExecutionOrder = Ordered.LOWEST_PRECEDENCE;\n\n\t/**\n\t * Establishes the default {@link Ordered} precedence for\n\t * {@link org.springframework.batch.core.StepExecutionListener}.\n\t */\n\tprivate int stepExecutionOrder = Ordered.LOWEST_PRECEDENCE;\n\n\t/**\n\t * Establishes the default {@link Ordered} precedence for\n\t * {@link org.springframework.batch.core.ItemReadListener}.\n\t */\n\tprivate int itemReadOrder = Ordered.LOWEST_PRECEDENCE;\n\n\t/**\n\t * Establishes the default {@link Ordered} precedence for\n\t * {@link org.springframework.batch.core.ItemProcessListener}.\n\t */\n\tprivate int itemProcessOrder = Ordered.LOWEST_PRECEDENCE;\n\n\t/**\n\t * Establishes the default {@link Ordered} precedence for\n\t * {@link org.springframework.batch.core.ItemWriteListener}.\n\t */\n\tprivate int itemWriteOrder = Ordered.LOWEST_PRECEDENCE;\n\n\t/**\n\t * Establishes the default {@link Ordered} precedence for\n\t * {@link org.springframework.batch.core.ChunkListener}.\n\t */\n\tprivate int chunkOrder = Ordered.LOWEST_PRECEDENCE;\n\n\t/**\n\t * Establishes the default {@link Ordered} precedence for\n\t * {@link org.springframework.batch.core.SkipListener}.\n\t */\n\tprivate int skipOrder = Ordered.LOWEST_PRECEDENCE;\n\n\tprivate String jobExecutionEventBindingName = \"job-execution-events\";\n\n\tprivate String skipEventBindingName = \"skip-events\";\n\n\tprivate String chunkEventBindingName = \"chunk-events\";\n\n\tprivate String itemProcessEventBindingName = \"item-process-events\";\n\n\tprivate String itemReadEventBindingName = \"item-read-events\";\n\n\tprivate String itemWriteEventBindingName = \"item-write-events\";\n\n\tprivate String stepExecutionEventBindingName = \"step-execution-events\";\n\n\tprivate String taskEventBindingName = \"task-events\";\n\n\tpublic int getJobExecutionOrder() {\n\t\treturn this.jobExecutionOrder;\n\t}\n\n\tpublic void setJobExecutionOrder(int jobExecutionOrder) {\n\t\tthis.jobExecutionOrder = jobExecutionOrder;\n\t}\n\n\tpublic int getStepExecutionOrder() {\n\t\treturn this.stepExecutionOrder;\n\t}\n\n\tpublic void setStepExecutionOrder(int stepExecutionOrder) {\n\t\tthis.stepExecutionOrder = stepExecutionOrder;\n\t}\n\n\tpublic int getItemReadOrder() {\n\t\treturn this.itemReadOrder;\n\t}\n\n\tpublic void setItemReadOrder(int itemReadOrder) {\n\t\tthis.itemReadOrder = itemReadOrder;\n\t}\n\n\tpublic int getItemProcessOrder() {\n\t\treturn this.itemProcessOrder;\n\t}\n\n\tpublic void setItemProcessOrder(int itemProcessOrder) {\n\t\tthis.itemProcessOrder = itemProcessOrder;\n\t}\n\n\tpublic int getItemWriteOrder() {\n\t\treturn this.itemWriteOrder;\n\t}\n\n\tpublic void setItemWriteOrder(int itemWriteOrder) {\n\t\tthis.itemWriteOrder = itemWriteOrder;\n\t}\n\n\tpublic int getChunkOrder() {\n\t\treturn this.chunkOrder;\n\t}\n\n\tpublic void setChunkOrder(int chunkOrder) {\n\t\tthis.chunkOrder = chunkOrder;\n\t}\n\n\tpublic int getSkipOrder() {\n\t\treturn this.skipOrder;\n\t}\n\n\tpublic void setSkipOrder(int skipOrder) {\n\t\tthis.skipOrder = skipOrder;\n\t}\n\n\tpublic String getJobExecutionEventBindingName() {\n\t\treturn jobExecutionEventBindingName;\n\t}\n\n\tpublic void setJobExecutionEventBindingName(String jobExecutionEventBindingName) {\n\t\tthis.jobExecutionEventBindingName = jobExecutionEventBindingName;\n\t}\n\n\tpublic String getSkipEventBindingName() {\n\t\treturn skipEventBindingName;\n\t}\n\n\tpublic void setSkipEventBindingName(String skipEventBindingName) {\n\t\tthis.skipEventBindingName = skipEventBindingName;\n\t}\n\n\tpublic String getChunkEventBindingName() {\n\t\treturn chunkEventBindingName;\n\t}\n\n\tpublic void setChunkEventBindingName(String chunkEventBindingName) {\n\t\tthis.chunkEventBindingName = chunkEventBindingName;\n\t}\n\n\tpublic String getItemProcessEventBindingName() {\n\t\treturn itemProcessEventBindingName;\n\t}\n\n\tpublic void setItemProcessEventBindingName(String itemProcessEventBindingName) {\n\t\tthis.itemProcessEventBindingName = itemProcessEventBindingName;\n\t}\n\n\tpublic String getItemReadEventBindingName() {\n\t\treturn itemReadEventBindingName;\n\t}\n\n\tpublic void setItemReadEventBindingName(String itemReadEventBindingName) {\n\t\tthis.itemReadEventBindingName = itemReadEventBindingName;\n\t}\n\n\tpublic String getItemWriteEventBindingName() {\n\t\treturn itemWriteEventBindingName;\n\t}\n\n\tpublic void setItemWriteEventBindingName(String itemWriteEventBindingName) {\n\t\tthis.itemWriteEventBindingName = itemWriteEventBindingName;\n\t}\n\n\tpublic String getStepExecutionEventBindingName() {\n\t\treturn stepExecutionEventBindingName;\n\t}\n\n\tpublic void setStepExecutionEventBindingName(String stepExecutionEventBindingName) {\n\t\tthis.stepExecutionEventBindingName = stepExecutionEventBindingName;\n\t}\n\n\tpublic String getTaskEventBindingName() {\n\t\treturn taskEventBindingName;\n\t}\n\n\tpublic void setTaskEventBindingName(String taskEventBindingName) {\n\t\tthis.taskEventBindingName = taskEventBindingName;\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/support/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Support classes for stream-based batch listener components in Spring Cloud Task.\n */\npackage org.springframework.cloud.task.batch.listener.support;\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/listener/TaskEventAutoConfiguration.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport org.springframework.boot.autoconfigure.AutoConfiguration;\nimport org.springframework.boot.autoconfigure.AutoConfigureAfter;\nimport org.springframework.boot.autoconfigure.AutoConfigureBefore;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.cloud.stream.config.BindingServiceConfiguration;\nimport org.springframework.cloud.stream.function.StreamBridge;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.repository.TaskExecution;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.PropertySource;\n\n/**\n * @author Michael Minella\n * @author Glenn Renfro\n */\n@AutoConfiguration\n@ConditionalOnClass(StreamBridge.class)\n@ConditionalOnBean(TaskLifecycleListener.class)\n@ConditionalOnExpression(\"T(org.springframework.util.StringUtils).isEmpty('${spring.batch.job.jobName:}')\")\n// @checkstyle:off\n@ConditionalOnProperty(prefix = \"spring.cloud.task.events\", name = \"enabled\", havingValue = \"true\",\n\t\tmatchIfMissing = true)\n// @checkstyle:on\n@PropertySource(\"classpath:/org/springframework/cloud/task/application.properties\")\n@AutoConfigureBefore(BindingServiceConfiguration.class)\n@AutoConfigureAfter(SimpleTaskAutoConfiguration.class)\n@EnableConfigurationProperties(TaskEventProperties.class)\npublic class TaskEventAutoConfiguration {\n\n\t/**\n\t * Configuration for a {@link TaskExecutionListener}.\n\t */\n\t@AutoConfiguration\n\tpublic static class ListenerConfiguration {\n\n\t\t@Bean\n\t\tpublic TaskExecutionListener taskEventEmitter(StreamBridge streamBridge,\n\t\t\t\tTaskEventProperties taskEventProperties) {\n\t\t\treturn new TaskExecutionListener() {\n\t\t\t\t@Override\n\t\t\t\tpublic void onTaskStartup(TaskExecution taskExecution) {\n\t\t\t\t\tstreamBridge.send(taskEventProperties.getTaskEventBindingName(), taskExecution);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onTaskEnd(TaskExecution taskExecution) {\n\t\t\t\t\tstreamBridge.send(taskEventProperties.getTaskEventBindingName(), taskExecution);\n\t\t\t\t}\n\n\t\t\t\t@Override\n\t\t\t\tpublic void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {\n\t\t\t\t\tstreamBridge.send(taskEventProperties.getTaskEventBindingName(), taskExecution);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/listener/package-info.java",
    "content": "/*\n * Copyright 2015-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Stream-based task lifecycle listener support for Spring Cloud Task.\n */\npackage org.springframework.cloud.task.listener;\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/resources/META-INF/additional-spring-configuration-metadata.json",
    "content": "{\n\t\"properties\": [\n\t\t{\n\t\t\t\"defaultValue\": true,\n\t\t\t\"name\": \"spring.cloud.task.events.enabled\",\n\t\t\t\"description\": \"This property is used to determine if a task app should emit task events.\",\n\t\t\t\"type\": \"java.lang.Boolean\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports",
    "content": "org.springframework.cloud.task.listener.TaskEventAutoConfiguration\norg.springframework.cloud.task.batch.listener.BatchEventAutoConfiguration\n"
  },
  {
    "path": "spring-cloud-task-stream/src/main/resources/org/springframework/cloud/task/application.properties",
    "content": "spring.cloud.stream.bindings.task-events.contentType=application/json\nspring.cloud.stream.bindings.item-write-events.contentType=application/json\nspring.cloud.stream.bindings.item-read-events.contentType=application/json\nspring.cloud.stream.bindings.item-process-events.contentType=application/json\nspring.cloud.stream.bindings.skip-events.contentType=application/json\nspring.cloud.stream.bindings.step-execution-events.contentType=application/json\nspring.cloud.stream.bindings.job-execution-events.contentType=application/json\n\n\n"
  },
  {
    "path": "spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/EventListenerTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\n\nimport org.junit.jupiter.api.AfterEach;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport tools.jackson.databind.DeserializationFeature;\nimport tools.jackson.databind.ObjectMapper;\nimport tools.jackson.databind.json.JsonMapper;\n\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.JobInstance;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.scope.context.ChunkContext;\nimport org.springframework.batch.core.scope.context.StepContext;\nimport org.springframework.batch.core.step.StepExecution;\nimport org.springframework.batch.infrastructure.item.Chunk;\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.cloud.stream.binder.test.OutputDestination;\nimport org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;\nimport org.springframework.cloud.stream.function.StreamBridge;\nimport org.springframework.cloud.task.batch.listener.support.JobExecutionEvent;\nimport org.springframework.cloud.task.batch.listener.support.MessagePublisher;\nimport org.springframework.cloud.task.batch.listener.support.StepExecutionEvent;\nimport org.springframework.cloud.task.batch.listener.support.TaskEventProperties;\nimport org.springframework.context.ConfigurableApplicationContext;\nimport org.springframework.core.Ordered;\nimport org.springframework.messaging.Message;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n * @author Ali Shahbour\n */\npublic class EventListenerTests {\n\n\tprivate EventEmittingSkipListener eventEmittingSkipListener;\n\n\tprivate EventEmittingItemProcessListener eventEmittingItemProcessListener;\n\n\tprivate EventEmittingItemReadListener eventEmittingItemReadListener;\n\n\tprivate EventEmittingItemWriteListener eventEmittingItemWriteListener;\n\n\tprivate EventEmittingJobExecutionListener eventEmittingJobExecutionListener;\n\n\tprivate EventEmittingStepExecutionListener eventEmittingStepExecutionListener;\n\n\tprivate EventEmittingChunkListener eventEmittingChunkListener;\n\n\tprivate ConfigurableApplicationContext applicationContext;\n\n\tprivate final TaskEventProperties taskEventProperties = new TaskEventProperties();\n\n\tprivate ObjectMapper objectMapper = new ObjectMapper();\n\n\t@BeforeEach\n\tpublic void beforeTests() {\n\t\tobjectMapper = JsonMapper.builder().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();\n\n\t\tthis.applicationContext = new SpringApplicationBuilder()\n\t\t\t.sources(TestChannelBinderConfiguration.getCompleteConfiguration(BatchEventsApplication.class))\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.build()\n\t\t\t.run();\n\t\tStreamBridge streamBridge = this.applicationContext.getBean(StreamBridge.class);\n\t\tMessagePublisher messagePublisher = new MessagePublisher(streamBridge);\n\n\t\tthis.eventEmittingSkipListener = new EventEmittingSkipListener(messagePublisher, this.taskEventProperties);\n\t\tthis.eventEmittingItemProcessListener = new EventEmittingItemProcessListener(messagePublisher,\n\t\t\t\tthis.taskEventProperties);\n\t\tthis.eventEmittingItemReadListener = new EventEmittingItemReadListener(messagePublisher,\n\t\t\t\tthis.taskEventProperties);\n\t\tthis.eventEmittingItemWriteListener = new EventEmittingItemWriteListener(messagePublisher,\n\t\t\t\tthis.taskEventProperties);\n\t\tthis.eventEmittingJobExecutionListener = new EventEmittingJobExecutionListener(messagePublisher,\n\t\t\t\tthis.taskEventProperties);\n\t\tthis.eventEmittingStepExecutionListener = new EventEmittingStepExecutionListener(messagePublisher,\n\t\t\t\tthis.taskEventProperties);\n\t\tthis.eventEmittingChunkListener = new EventEmittingChunkListener(messagePublisher, 0, this.taskEventProperties);\n\t}\n\n\t@AfterEach\n\tpublic void tearDown() {\n\t\tif (this.applicationContext != null && this.applicationContext.isActive()) {\n\t\t\tthis.applicationContext.close();\n\t\t}\n\t}\n\n\t@Test\n\tpublic void testEventListenerOrderProperty() {\n\t\tassertThat(Ordered.LOWEST_PRECEDENCE).isEqualTo(this.eventEmittingSkipListener.getOrder());\n\t\tassertThat(Ordered.LOWEST_PRECEDENCE).isEqualTo(this.eventEmittingItemProcessListener.getOrder());\n\t\tassertThat(Ordered.LOWEST_PRECEDENCE).isEqualTo(this.eventEmittingItemReadListener.getOrder());\n\t\tassertThat(Ordered.LOWEST_PRECEDENCE).isEqualTo(this.eventEmittingItemWriteListener.getOrder());\n\t\tassertThat(Ordered.LOWEST_PRECEDENCE).isEqualTo(this.eventEmittingJobExecutionListener.getOrder());\n\t\tassertThat(Ordered.LOWEST_PRECEDENCE).isEqualTo(this.eventEmittingStepExecutionListener.getOrder());\n\t\tassertThat(0).isEqualTo(this.eventEmittingChunkListener.getOrder());\n\t}\n\n\t@Test\n\tpublic void testItemProcessListenerOnProcessorError() {\n\t\tthis.eventEmittingItemProcessListener.onProcessError(\"HELLO\", new RuntimeException(\"Test Exception\"));\n\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getItemProcessEventBindingName()))\n\t\t\t.isEqualTo(\"Exception while item was being processed\");\n\t}\n\n\t@Test\n\tpublic void testItemProcessListenerAfterProcess() {\n\t\tthis.eventEmittingItemProcessListener.afterProcess(\"HELLO_AFTER_PROCESS_EQUAL\", \"HELLO_AFTER_PROCESS_EQUAL\");\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getItemProcessEventBindingName()))\n\t\t\t.isEqualTo(\"item equaled result after processing\");\n\n\t\tthis.eventEmittingItemProcessListener.afterProcess(\"HELLO_NOT_EQUAL\", \"WORLD\");\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getItemProcessEventBindingName()))\n\t\t\t.isEqualTo(\"item did not equal result after processing\");\n\n\t\tthis.eventEmittingItemProcessListener.afterProcess(\"HELLO_AFTER_PROCESS\", null);\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getItemProcessEventBindingName()))\n\t\t\t.isEqualTo(\"1 item was filtered\");\n\t}\n\n\t@Test\n\tpublic void testItemProcessBeforeProcessor() {\n\t\tthis.eventEmittingItemProcessListener.beforeProcess(\"HELLO_BEFORE_PROCESS\");\n\t\tassertNoMessageFromDestination(this.taskEventProperties.getItemProcessEventBindingName());\n\t}\n\n\t@Test\n\tpublic void EventEmittingSkipListenerSkipRead() {\n\t\tthis.eventEmittingSkipListener.onSkipInRead(new RuntimeException(\"Text Exception\"));\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getSkipEventBindingName()))\n\t\t\t.isEqualTo(\"Skipped when reading.\");\n\t}\n\n\t@Test\n\tpublic void EventEmittingSkipListenerSkipWrite() {\n\t\tfinal String MESSAGE = \"\\\"HELLO_SKIP_WRITE\\\"\";\n\t\tthis.eventEmittingSkipListener.onSkipInWrite(MESSAGE, new RuntimeException(\"Text Exception\"));\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getSkipEventBindingName())).isEqualTo(MESSAGE);\n\t}\n\n\t@Test\n\tpublic void EventEmittingSkipListenerSkipProcess() {\n\t\tfinal String MESSAGE = \"\\\"HELLO_SKIP_PROCESS\\\"\";\n\t\tthis.eventEmittingSkipListener.onSkipInProcess(MESSAGE, new RuntimeException(\"Text Exception\"));\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getSkipEventBindingName())).isEqualTo(MESSAGE);\n\t}\n\n\t@Test\n\tpublic void EventEmittingItemReadListener() {\n\t\tthis.eventEmittingItemReadListener.onReadError(new RuntimeException(\"Text Exception\"));\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getItemReadEventBindingName()))\n\t\t\t.isEqualTo(\"Exception while item was being read\");\n\t}\n\n\t@Test\n\tpublic void EventEmittingItemReadListenerBeforeRead() {\n\t\tthis.eventEmittingItemReadListener.beforeRead();\n\t\tassertNoMessageFromDestination(this.taskEventProperties.getItemReadEventBindingName());\n\t}\n\n\t@Test\n\tpublic void EventEmittingItemReadListenerAfterRead() {\n\t\tthis.eventEmittingItemReadListener.afterRead(\"HELLO_AFTER_READ\");\n\t\tassertNoMessageFromDestination(this.taskEventProperties.getItemReadEventBindingName());\n\t}\n\n\t@Test\n\tpublic void EventEmittingItemWriteListenerBeforeWrite() {\n\t\tthis.eventEmittingItemWriteListener.beforeWrite(getSampleList());\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getItemWriteEventBindingName()))\n\t\t\t.isEqualTo(\"3 items to be written.\");\n\t}\n\n\t@Test\n\tpublic void EventEmittingItemWriteListenerAfterWrite() {\n\t\tthis.eventEmittingItemWriteListener.afterWrite(getSampleList());\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getItemWriteEventBindingName()))\n\t\t\t.isEqualTo(\"3 items have been written.\");\n\t}\n\n\t@Test\n\tpublic void EventEmittingItemWriteListenerWriteError() {\n\t\tRuntimeException exception = new RuntimeException(\"Text Exception\");\n\t\tthis.eventEmittingItemWriteListener.onWriteError(exception, getSampleList());\n\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getItemWriteEventBindingName()))\n\t\t\t.isEqualTo(\"Exception while 3 items are attempted to be written.\");\n\t}\n\n\t@Test\n\tpublic void EventEmittingJobExecutionListenerBeforeJob() throws IOException {\n\t\tJobExecution jobExecution = getJobExecution();\n\t\tthis.eventEmittingJobExecutionListener.beforeJob(jobExecution);\n\t\tList<Message<byte[]>> result = testListener(this.taskEventProperties.getJobExecutionEventBindingName(), 1);\n\t\tassertThat(result.get(0)).isNotNull();\n\n\t\tJobExecutionEvent jobEvent = this.objectMapper.readValue(result.get(0).getPayload(), JobExecutionEvent.class);\n\t\tassertThat(jobEvent.getJobInstance().getJobName()).isEqualTo(jobExecution.getJobInstance().getJobName());\n\t}\n\n\t@Test\n\tpublic void EventEmittingJobExecutionListenerAfterJob() throws IOException {\n\t\tJobExecution jobExecution = getJobExecution();\n\t\tthis.eventEmittingJobExecutionListener.afterJob(jobExecution);\n\t\tList<Message<byte[]>> result = testListener(this.taskEventProperties.getJobExecutionEventBindingName(), 1);\n\t\tassertThat(result.get(0)).isNotNull();\n\n\t\tJobExecutionEvent jobEvent = this.objectMapper.readValue(result.get(0).getPayload(), JobExecutionEvent.class);\n\t\tassertThat(jobEvent.getJobInstance().getJobName()).isEqualTo(jobExecution.getJobInstance().getJobName());\n\t}\n\n\t@Test\n\tpublic void EventEmittingStepExecutionListenerBeforeStep() throws IOException {\n\t\tfinal String STEP_MESSAGE = \"BEFORE_STEP_MESSAGE\";\n\t\tStepExecution stepExecution = new StepExecution(STEP_MESSAGE, getJobExecution());\n\t\tthis.eventEmittingStepExecutionListener.beforeStep(stepExecution);\n\n\t\tList<Message<byte[]>> result = testListener(this.taskEventProperties.getStepExecutionEventBindingName(), 1);\n\t\tassertThat(result.get(0)).isNotNull();\n\n\t\tStepExecutionEvent stepExecutionEvent = this.objectMapper.readValue(result.get(0).getPayload(),\n\t\t\t\tStepExecutionEvent.class);\n\t\tassertThat(stepExecutionEvent.getStepName()).isEqualTo(STEP_MESSAGE);\n\t}\n\n\t@Test\n\tpublic void EventEmittingStepExecutionListenerAfterStep() throws IOException {\n\t\tfinal String STEP_MESSAGE = \"AFTER_STEP_MESSAGE\";\n\t\tStepExecution stepExecution = new StepExecution(STEP_MESSAGE, getJobExecution());\n\t\tthis.eventEmittingStepExecutionListener.afterStep(stepExecution);\n\t\tList<Message<byte[]>> result = testListener(this.taskEventProperties.getStepExecutionEventBindingName(), 1);\n\n\t\tassertThat(result.get(0)).isNotNull();\n\t\tStepExecutionEvent stepExecutionEvent = this.objectMapper.readValue(result.get(0).getPayload(),\n\t\t\t\tStepExecutionEvent.class);\n\t\tassertThat(stepExecutionEvent.getStepName()).isEqualTo(STEP_MESSAGE);\n\t}\n\n\t@Test\n\tpublic void EventEmittingChunkExecutionListenerBeforeChunk() {\n\t\tfinal String CHUNK_MESSAGE = \"Before Chunk Processing\";\n\t\tthis.eventEmittingChunkListener.beforeChunk(new Chunk<>(CHUNK_MESSAGE));\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getChunkEventBindingName()))\n\t\t\t.isEqualTo(CHUNK_MESSAGE);\n\t}\n\n\t@Test\n\tpublic void EventEmittingChunkExecutionListenerAfterChunk() {\n\t\tfinal String CHUNK_MESSAGE = \"After Chunk Processing\";\n\t\tthis.eventEmittingChunkListener.afterChunk(new Chunk<>());\n\t\tassertThat(getStringFromDestination(this.taskEventProperties.getChunkEventBindingName()))\n\t\t\t.isEqualTo(CHUNK_MESSAGE);\n\t}\n\n\t@Test\n\tpublic void EventEmittingChunkExecutionListenerAfterChunkError() {\n\t\tthis.eventEmittingChunkListener.afterChunkError(getChunkContext());\n\t\tassertNoMessageFromDestination(this.taskEventProperties.getChunkEventBindingName());\n\t}\n\n\tprivate JobExecution getJobExecution() {\n\t\tfinal String JOB_NAME = UUID.randomUUID().toString();\n\t\tJobInstance jobInstance = new JobInstance(1L, JOB_NAME);\n\t\treturn new JobExecution(1L, jobInstance, new JobParameters());\n\t}\n\n\tprivate Chunk<String> getSampleList() {\n\t\tList<String> testList = new ArrayList<>(3);\n\t\ttestList.add(\"Hello\");\n\t\ttestList.add(\"World\");\n\t\ttestList.add(\"foo\");\n\t\treturn new Chunk<String>(testList);\n\t}\n\n\tprivate ChunkContext getChunkContext() {\n\t\tJobExecution jobExecution = getJobExecution();\n\t\tStepExecution stepExecution = new StepExecution(\"STEP1\", jobExecution);\n\t\tStepContext stepContext = new StepContext(stepExecution);\n\t\tChunkContext chunkContext = new ChunkContext(stepContext);\n\t\treturn chunkContext;\n\t}\n\n\tprivate List<Message<byte[]>> testListener(String bindingName, int numberToRead) {\n\t\tList<Message<byte[]>> results = new ArrayList<>();\n\t\tOutputDestination target = this.applicationContext.getBean(OutputDestination.class);\n\t\tfor (int i = 0; i < numberToRead; i++) {\n\t\t\tresults.add(target.receive(10000, bindingName));\n\t\t}\n\t\treturn results;\n\t}\n\n\tprivate String getStringFromDestination(String bindingName) {\n\t\tList<Message<byte[]>> result = testListener(bindingName, 1);\n\t\tassertThat(result.get(0)).isNotNull();\n\n\t\tassertThat(new String(result.get(0).getPayload()));\n\t\treturn new String(result.get(0).getPayload());\n\t}\n\n\tprivate void assertNoMessageFromDestination(String bindingName) {\n\t\tList<Message<byte[]>> result = testListener(bindingName, 1);\n\t\tassertThat(result.get(0)).isNull();\n\t}\n\n\t@SpringBootApplication\n\tpublic static class BatchEventsApplication {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobExecutionEventTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport java.time.LocalDateTime;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.BatchStatus;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.JobInstance;\nimport org.springframework.batch.core.job.parameters.JobParameter;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.step.StepExecution;\nimport org.springframework.batch.infrastructure.item.ExecutionContext;\nimport org.springframework.beans.factory.NoSuchBeanDefinitionException;\nimport org.springframework.boot.autoconfigure.AutoConfigurations;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;\nimport org.springframework.boot.test.context.runner.ApplicationContextRunner;\nimport org.springframework.cloud.task.batch.listener.support.JobExecutionEvent;\nimport org.springframework.cloud.task.batch.listener.support.JobInstanceEvent;\nimport org.springframework.cloud.task.batch.listener.support.JobParameterEvent;\nimport org.springframework.cloud.task.batch.listener.support.StepExecutionEvent;\nimport org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;\nimport org.springframework.cloud.task.configuration.SingleTaskConfiguration;\nimport org.springframework.core.Ordered;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.assertj.core.api.Assertions.assertThatThrownBy;\n\n/**\n * @author Glenn Renfro.\n * @author Ali Shahbour\n */\npublic class JobExecutionEventTests {\n\n\tprivate static final String JOB_NAME = \"FOODJOB\";\n\n\tprivate static final Long JOB_INSTANCE_ID = 1L;\n\n\tprivate static final Long JOB_EXECUTION_ID = 2L;\n\n\tprivate static final String[] LISTENER_BEAN_NAMES = { BatchEventAutoConfiguration.JOB_EXECUTION_EVENTS_LISTENER,\n\t\t\tBatchEventAutoConfiguration.STEP_EXECUTION_EVENTS_LISTENER,\n\t\t\tBatchEventAutoConfiguration.CHUNK_EVENTS_LISTENER, BatchEventAutoConfiguration.ITEM_READ_EVENTS_LISTENER,\n\t\t\tBatchEventAutoConfiguration.ITEM_WRITE_EVENTS_LISTENER,\n\t\t\tBatchEventAutoConfiguration.ITEM_PROCESS_EVENTS_LISTENER,\n\t\t\tBatchEventAutoConfiguration.SKIP_EVENTS_LISTENER };\n\n\tprivate JobParameters jobParameters;\n\n\tprivate JobInstance jobInstance;\n\n\t@BeforeEach\n\tpublic void setup() {\n\t\tthis.jobInstance = new JobInstance(JOB_INSTANCE_ID, JOB_NAME);\n\t\tthis.jobParameters = new JobParameters();\n\t}\n\n\t@Test\n\tpublic void testBasic() {\n\t\tJobExecution jobExecution;\n\t\tjobExecution = new JobExecution(JOB_EXECUTION_ID, this.jobInstance, this.jobParameters);\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent(jobExecution);\n\t\tassertThat(jobExecutionEvent.getJobInstance()).as(\"jobInstance should not be null\").isNotNull();\n\t\tassertThat(jobExecutionEvent.getJobParameters()).as(\"jobParameters should not be null\").isNotNull();\n\n\t\tassertThat(jobExecutionEvent.getJobParameters().getParameters().size()).as(\"jobParameters size did not match\")\n\t\t\t.isEqualTo(0);\n\t\tassertThat(jobExecutionEvent.getJobInstance().getJobName()).as(\"jobInstance name did not match\")\n\t\t\t.isEqualTo(JOB_NAME);\n\t\tassertThat(jobExecutionEvent.getStepExecutions().size()).as(\"no step executions were expected\").isEqualTo(0);\n\t\tassertThat(jobExecutionEvent.getExitStatus().getExitCode()).as(\"exitStatus did not match expected\")\n\t\t\t.isEqualTo(\"UNKNOWN\");\n\t}\n\n\t@Test\n\tpublic void testJobParameters() {\n\t\tString[] JOB_PARAM_KEYS = { \"A\", \"B\", \"C\", \"D\" };\n\t\tDate testDate = new Date();\n\t\tJobParameter[] PARAMETERS = { new JobParameter(\"A\", \"FOO\", String.class), new JobParameter(\"B\", 1L, Long.class),\n\t\t\t\tnew JobParameter(\"C\", 1D, Double.class), new JobParameter(\"D\", testDate, Date.class) };\n\n\t\tSet<JobParameter<?>> jobParamMap = new HashSet<>();\n\t\tfor (int paramCount = 0; paramCount < JOB_PARAM_KEYS.length; paramCount++) {\n\t\t\tjobParamMap.add(PARAMETERS[paramCount]);\n\t\t}\n\t\tthis.jobParameters = new JobParameters(jobParamMap);\n\t\tJobExecution jobExecution;\n\t\tjobExecution = new JobExecution(JOB_EXECUTION_ID, this.jobInstance, this.jobParameters);\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent(jobExecution);\n\n\t\tassertThat(jobExecutionEvent.getJobParameters().getParameters()).contains(new JobParameterEvent(PARAMETERS[0]),\n\t\t\t\tnew JobParameterEvent(PARAMETERS[1]), new JobParameterEvent(PARAMETERS[2]),\n\t\t\t\tnew JobParameterEvent(PARAMETERS[3]));\n\t}\n\n\t@Test\n\tpublic void testStepExecutions() {\n\t\tJobExecution jobExecution;\n\t\tjobExecution = new JobExecution(JOB_EXECUTION_ID, this.jobInstance, this.jobParameters);\n\t\tList<StepExecution> stepsExecutions = new ArrayList<>();\n\t\tstepsExecutions.add(new StepExecution(0, \"foo\", jobExecution));\n\t\tstepsExecutions.add(new StepExecution(1, \"bar\", jobExecution));\n\t\tstepsExecutions.add(new StepExecution(2, \"baz\", jobExecution));\n\t\tjobExecution.addStepExecutions(stepsExecutions);\n\n\t\tJobExecutionEvent jobExecutionsEvent = new JobExecutionEvent(jobExecution);\n\t\tassertThat(jobExecutionsEvent.getStepExecutions().size()).as(\"stepExecutions count is incorrect\").isEqualTo(3);\n\t\tIterator<StepExecutionEvent> iter = jobExecutionsEvent.getStepExecutions().iterator();\n\t\tassertThat(iter.next().getStepName()).as(\"foo stepExecution is not present\").isEqualTo(\"foo\");\n\t\tassertThat(iter.next().getStepName()).as(\"bar stepExecution is not present\").isEqualTo(\"bar\");\n\t\tassertThat(iter.next().getStepName()).as(\"baz stepExecution is not present\").isEqualTo(\"baz\");\n\t}\n\n\t@Test\n\tpublic void testDefaultConfiguration() {\n\t\ttestDisabledConfiguration(null, null);\n\t}\n\n\t@Test\n\tpublic void testDisabledJobExecutionListener() {\n\t\ttestDisabledConfiguration(\"spring.cloud.task.batch.events.job-execution.enabled\",\n\t\t\t\tBatchEventAutoConfiguration.JOB_EXECUTION_EVENTS_LISTENER);\n\t}\n\n\t@Test\n\tpublic void testDisabledStepExecutionListener() {\n\t\ttestDisabledConfiguration(\"spring.cloud.task.batch.events.step-execution.enabled\",\n\t\t\t\tBatchEventAutoConfiguration.STEP_EXECUTION_EVENTS_LISTENER);\n\t}\n\n\t@Test\n\tpublic void testDisabledChunkListener() {\n\t\ttestDisabledConfiguration(\"spring.cloud.task.batch.events.chunk.enabled\",\n\t\t\t\tBatchEventAutoConfiguration.CHUNK_EVENTS_LISTENER);\n\t}\n\n\t@Test\n\tpublic void testDisabledItemReadListener() {\n\t\ttestDisabledConfiguration(\"spring.cloud.task.batch.events.item-read.enabled\",\n\t\t\t\tBatchEventAutoConfiguration.ITEM_READ_EVENTS_LISTENER);\n\t}\n\n\t@Test\n\tpublic void testDisabledItemWriteListener() {\n\t\ttestDisabledConfiguration(\"spring.cloud.task.batch.events.item-write.enabled\",\n\t\t\t\tBatchEventAutoConfiguration.ITEM_WRITE_EVENTS_LISTENER);\n\t}\n\n\t@Test\n\tpublic void testDisabledItemProcessListener() {\n\t\ttestDisabledConfiguration(\"spring.cloud.task.batch.events.item-process.enabled\",\n\t\t\t\tBatchEventAutoConfiguration.ITEM_PROCESS_EVENTS_LISTENER);\n\t}\n\n\t@Test\n\tpublic void testDisabledSkipEventListener() {\n\t\ttestDisabledConfiguration(\"spring.cloud.task.batch.events.skip.enabled\",\n\t\t\t\tBatchEventAutoConfiguration.SKIP_EVENTS_LISTENER);\n\t}\n\n\t@Test\n\tpublic void testDefaultConstructor() {\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent();\n\t\tassertThat(jobExecutionEvent.getExitStatus().getExitCode()).isEqualTo(\"UNKNOWN\");\n\t}\n\n\t@Test\n\tpublic void testFailureExceptions() {\n\t\tfinal String EXCEPTION_MESSAGE = \"TEST EXCEPTION\";\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent();\n\t\tassertThat(jobExecutionEvent.getFailureExceptions().size()).isEqualTo(0);\n\t\tjobExecutionEvent.addFailureException(new IllegalStateException(EXCEPTION_MESSAGE));\n\t\tassertThat(jobExecutionEvent.getFailureExceptions().size()).isEqualTo(1);\n\t\tassertThat(jobExecutionEvent.getAllFailureExceptions().size()).isEqualTo(1);\n\t\tassertThat(EXCEPTION_MESSAGE).isEqualTo(jobExecutionEvent.getFailureExceptions().get(0).getMessage());\n\t\tassertThat(EXCEPTION_MESSAGE).isEqualTo(jobExecutionEvent.getAllFailureExceptions().get(0).getMessage());\n\t}\n\n\t@Test\n\tpublic void testToString() {\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent();\n\t\tassertThat(jobExecutionEvent.toString().startsWith(\"JobExecutionEvent:\")).isTrue();\n\t}\n\n\t@Test\n\tpublic void testGetterSetters() {\n\t\tLocalDateTime date = LocalDateTime.now();\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent();\n\t\tjobExecutionEvent.setLastUpdated(date);\n\t\tassertThat(jobExecutionEvent.getLastUpdated()).isEqualTo(date);\n\t\tjobExecutionEvent.setCreateTime(date);\n\t\tassertThat(jobExecutionEvent.getCreateTime()).isEqualTo(date);\n\t\tjobExecutionEvent.setEndTime(date);\n\t\tassertThat(jobExecutionEvent.getEndTime()).isEqualTo(date);\n\t\tjobExecutionEvent.setStartTime(date);\n\t\tassertThat(jobExecutionEvent.getStartTime()).isEqualTo(date);\n\t}\n\n\t@Test\n\tpublic void testExitStatus() {\n\t\tfinal String EXIT_CODE = \"KNOWN\";\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent();\n\t\tassertThat(jobExecutionEvent.getExitStatus().getExitCode()).isEqualTo(\"UNKNOWN\");\n\t\torg.springframework.cloud.task.batch.listener.support.ExitStatus expectedExitStatus;\n\t\texpectedExitStatus = new org.springframework.cloud.task.batch.listener.support.ExitStatus();\n\t\texpectedExitStatus.setExitCode(EXIT_CODE);\n\t\tjobExecutionEvent.setExitStatus(expectedExitStatus);\n\t\tassertThat(jobExecutionEvent.getExitStatus().getExitCode()).isEqualTo(EXIT_CODE);\n\t}\n\n\t@Test\n\tpublic void testJobInstance() {\n\t\tfinal String JOB_NAME = \"KNOWN\";\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent();\n\t\tassertThat(jobExecutionEvent.getJobInstance()).isNull();\n\t\tassertThat(jobExecutionEvent.getJobId()).isNull();\n\t\tJobInstanceEvent expectedJobInstanceEvent = new JobInstanceEvent(1L, JOB_NAME);\n\t\tjobExecutionEvent.setJobInstance(expectedJobInstanceEvent);\n\t\tassertThat(jobExecutionEvent.getJobInstance().getJobName()).isEqualTo(expectedJobInstanceEvent.getJobName());\n\t\tassertThat(jobExecutionEvent.getJobId()).isEqualTo(expectedJobInstanceEvent.getId());\n\t}\n\n\t@Test\n\tpublic void testExecutionContext() {\n\t\tExecutionContext executionContext = new ExecutionContext();\n\t\texecutionContext.put(\"hello\", \"world\");\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent();\n\t\tassertThat(jobExecutionEvent.getExecutionContext()).isNotNull();\n\t\tjobExecutionEvent.setExecutionContext(executionContext);\n\t\tassertThat(jobExecutionEvent.getExecutionContext().getString(\"hello\")).isEqualTo(\"world\");\n\t}\n\n\t@Test\n\tpublic void testBatchStatus() {\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent();\n\t\tassertThat(jobExecutionEvent.getStatus()).isEqualTo(BatchStatus.STARTING);\n\t\tjobExecutionEvent.setStatus(BatchStatus.ABANDONED);\n\t\tassertThat(jobExecutionEvent.getStatus()).isEqualTo(BatchStatus.ABANDONED);\n\t}\n\n\t@Test\n\tpublic void testUpgradeBatchStatus() {\n\t\tJobExecutionEvent jobExecutionEvent = new JobExecutionEvent();\n\t\tassertThat(jobExecutionEvent.getStatus()).isEqualTo(BatchStatus.STARTING);\n\t\tjobExecutionEvent.upgradeStatus(BatchStatus.FAILED);\n\t\tassertThat(jobExecutionEvent.getStatus()).isEqualTo(BatchStatus.FAILED);\n\t\tjobExecutionEvent.upgradeStatus(BatchStatus.COMPLETED);\n\t\tassertThat(jobExecutionEvent.getStatus()).isEqualTo(BatchStatus.FAILED);\n\t}\n\n\t@Test\n\tpublic void testOrderConfiguration() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))\n\t\t\t.withUserConfiguration(BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class)\n\t\t\t.withBean(\"org.springframework.cloud.task.batch.listener.JobExecutionEventTests$BatchEventTestApplication\",\n\t\t\t\t\tBatchEventTestApplication.class)\n\t\t\t.withPropertyValues(\"--spring.cloud.task.closecontext_enabled=false\", \"--spring.main.web-environment=false\",\n\t\t\t\t\t\"--spring.cloud.task.batch.events.chunk-order=5\",\n\t\t\t\t\t\"--spring.cloud.task.batch.events.item-process-order=5\",\n\t\t\t\t\t\"--spring.cloud.task.batch.events.item-read-order=5\",\n\t\t\t\t\t\"--spring.cloud.task.batch.events.item-write-order=5\",\n\t\t\t\t\t\"--spring.cloud.task.batch.events.job-execution-order=5\",\n\t\t\t\t\t\"--spring.cloud.task.batch.events.skip-order=5\",\n\t\t\t\t\t\"--spring.cloud.task.batch.events.step-execution-order=5\");\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tfor (String beanName : LISTENER_BEAN_NAMES) {\n\t\t\t\tOrdered ordered = (Ordered) context.getBean(beanName);\n\t\t\t\tassertThat(5).as(\"Expected order value of 5 for \" + beanName).isEqualTo(ordered.getOrder());\n\t\t\t}\n\n\t\t});\n\t}\n\n\t@Test\n\tpublic void singleStepBatchJobSkip() {\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))\n\t\t\t.withUserConfiguration(BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class)\n\t\t\t.withBean(\"org.springframework.cloud.task.batch.listener.JobExecutionEventTests$BatchEventTestApplication\",\n\t\t\t\t\tBatchEventTestApplication.class)\n\t\t\t.withPropertyValues(\"--spring.cloud.task.closecontext_enabled=false\", \"--spring.main.web-environment=false\",\n\t\t\t\t\t\"spring.batch.job.jobName=FOO\");\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tassertThatThrownBy(() -> context.getBean(\"jobExecutionEventsListener\"))\n\t\t\t\t.isInstanceOf(NoSuchBeanDefinitionException.class)\n\t\t\t\t.hasMessageContaining(\"No bean named 'jobExecutionEventsListener' available\");\n\t\t});\n\t}\n\n\tprivate void testDisabledConfiguration(String property, String disabledListener) {\n\t\tString disabledPropertyArg = (property != null) ? \"--\" + property + \"=false\" : \"\";\n\t\tApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()\n\t\t\t.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,\n\t\t\t\t\tSimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))\n\t\t\t.withUserConfiguration(BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class)\n\t\t\t.withBean(\"org.springframework.cloud.task.batch.listener.JobExecutionEventTests$BatchEventTestApplication\",\n\t\t\t\t\tBatchEventTestApplication.class)\n\t\t\t.withPropertyValues(\"--spring.cloud.task.closecontext_enabled=false\", \"--spring.main.web-environment=false\",\n\t\t\t\t\tdisabledPropertyArg);\n\t\tapplicationContextRunner.run((context) -> {\n\t\t\tboolean exceptionThrown = false;\n\t\t\tfor (String beanName : LISTENER_BEAN_NAMES) {\n\t\t\t\tif (disabledListener != null && disabledListener.equals(beanName)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tcontext.getBean(disabledListener);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (NoSuchBeanDefinitionException nsbde) {\n\t\t\t\t\t\texceptionThrown = true;\n\t\t\t\t\t}\n\t\t\t\t\tassertThat(exceptionThrown).as(String.format(\"Did not expect %s bean in context\", beanName))\n\t\t\t\t\t\t.isTrue();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcontext.getBean(beanName);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t@SpringBootApplication\n\tpublic static class BatchEventTestApplication {\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobInstanceEventTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.cloud.task.batch.listener.support.JobInstanceEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n */\npublic class JobInstanceEventTests {\n\n\tprivate static final long INSTANCE_ID = 1;\n\n\tprivate static final String JOB_NAME = \"FOOBAR\";\n\n\t@Test\n\tpublic void testConstructor() {\n\t\tJobInstanceEvent jobInstanceEvent = new JobInstanceEvent(INSTANCE_ID, JOB_NAME);\n\t\tassertThat(jobInstanceEvent.getInstanceId()).isEqualTo(INSTANCE_ID);\n\t\tassertThat(jobInstanceEvent.getJobName()).isEqualTo(JOB_NAME);\n\t}\n\n\t@Test\n\tpublic void testEmptyConstructor() {\n\t\tJobInstanceEvent jobInstanceEvent = new JobInstanceEvent();\n\t\tassertThat(jobInstanceEvent.getJobName()).isNull();\n\t}\n\n\t@Test\n\tpublic void testEmptyConstructorEmptyId() {\n\t\tJobInstanceEvent jobInstanceEvent = new JobInstanceEvent();\n\t\tjobInstanceEvent.getInstanceId();\n\t}\n\n\t@Test\n\tpublic void testToString() {\n\t\tJobInstanceEvent jobInstanceEvent = new JobInstanceEvent(INSTANCE_ID, JOB_NAME);\n\t\tassertThat(jobInstanceEvent.toString()).isEqualTo(\"JobInstanceEvent: id=1, version=null, Job=[FOOBAR]\");\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobParameterEventTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport java.time.LocalDateTime;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.parameters.JobParameter;\nimport org.springframework.cloud.task.batch.listener.support.JobParameterEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n */\npublic class JobParameterEventTests {\n\n\t@Test\n\tpublic void testDefaultConstructor() {\n\t\tJobParameterEvent jobParameterEvent = new JobParameterEvent();\n\t\tassertThat(jobParameterEvent.getValue()).isNull();\n\t\tassertThat(jobParameterEvent.isIdentifying()).isFalse();\n\t\tassertThat(jobParameterEvent).isEqualTo(new JobParameterEvent());\n\t}\n\n\t@Test\n\tpublic void testConstructor() {\n\t\tfinal String EXPECTED_VALUE = \"FOO\";\n\t\tfinal LocalDateTime EXPECTED_DATE_VALUE = LocalDateTime.now();\n\t\tJobParameter<?> jobParameter = new JobParameter<>(EXPECTED_VALUE + \"Key\", EXPECTED_VALUE, String.class);\n\t\tJobParameterEvent jobParameterEvent = new JobParameterEvent(jobParameter);\n\t\tassertThat(jobParameterEvent.getValue()).isEqualTo(EXPECTED_VALUE);\n\t\tassertThat(jobParameterEvent.isIdentifying()).isTrue();\n\n\t\tjobParameter = new JobParameter<>(\"dateKey\", EXPECTED_DATE_VALUE, LocalDateTime.class);\n\t\tjobParameterEvent = new JobParameterEvent(jobParameter);\n\t\tassertThat(jobParameterEvent.getValue()).isEqualTo(EXPECTED_DATE_VALUE);\n\t\tassertThat(jobParameterEvent.isIdentifying()).isTrue();\n\t\tassertThat(new JobParameterEvent(jobParameter).equals(jobParameterEvent)).isTrue();\n\t}\n\n\t@Test\n\tpublic void testEquals() {\n\t\tfinal String EXPECTED_VALUE = \"FOO\";\n\t\tJobParameter<?> jobParameter = new JobParameter<>(EXPECTED_VALUE + \"Key\", EXPECTED_VALUE, String.class);\n\t\tJobParameterEvent jobParameterEvent = new JobParameterEvent(jobParameter);\n\t\tJobParameterEvent anotherJobParameterEvent = new JobParameterEvent(jobParameter);\n\n\t\tassertThat(jobParameterEvent.equals(jobParameterEvent)).isTrue();\n\t\tassertThat(jobParameterEvent.equals(\"nope\")).isFalse();\n\t\tassertThat(jobParameterEvent.equals(anotherJobParameterEvent)).isTrue();\n\t}\n\n\t@Test\n\tpublic void testValidHashCode() {\n\t\tfinal String EXPECTED_VALUE = \"FOO\";\n\t\tJobParameter<?> jobParameter = new JobParameter<>(EXPECTED_VALUE + \"Key\", EXPECTED_VALUE, String.class);\n\t\tJobParameterEvent jobParameterEvent = new JobParameterEvent(jobParameter);\n\t\tassertThat(jobParameterEvent.hashCode()).isNotNull();\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobParametersEventTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.job.parameters.JobParameter;\nimport org.springframework.cloud.task.batch.listener.support.JobParameterEvent;\nimport org.springframework.cloud.task.batch.listener.support.JobParametersEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n */\npublic class JobParametersEventTests {\n\n\tprivate final static String DATE_KEY = \"DATE_KEY\";\n\n\tprivate final static String STRING_KEY = \"STRING_KEY\";\n\n\tprivate final static String LONG_KEY = \"LONG_KEY\";\n\n\tprivate final static String DOUBLE_KEY = \"DOUBLE_KEY\";\n\n\tprivate final static JobParameter<String> STRING_PARAM = new JobParameter<>(STRING_KEY, \"FOO\", String.class);\n\n\tprivate final static JobParameter<Date> DATE_PARAM = new JobParameter<>(DATE_KEY, new Date(), Date.class);\n\n\tprivate final static JobParameter<Long> LONG_PARAM = new JobParameter<>(LONG_KEY, 1L, Long.class);\n\n\tprivate final static JobParameter<Double> DOUBLE_PARAM = new JobParameter<>(DOUBLE_KEY, 2D, Double.class);\n\n\t@Test\n\tpublic void testDefaultConstructor() {\n\t\tJobParametersEvent jobParametersEvent = new JobParametersEvent();\n\t\tassertThat(jobParametersEvent.getParameters().size()).isEqualTo(0);\n\t\tassertThat(jobParametersEvent.isEmpty()).isTrue();\n\t}\n\n\t@Test\n\tpublic void testConstructor() {\n\t\tJobParametersEvent jobParametersEvent = getPopulatedParametersEvent();\n\t\tSet<JobParameterEvent> jobParameters = jobParametersEvent.getParameters();\n\t\tassertThat(jobParametersEvent.getParameters()).contains(new JobParameterEvent(STRING_PARAM),\n\t\t\t\tnew JobParameterEvent(DATE_PARAM), new JobParameterEvent(LONG_PARAM),\n\t\t\t\tnew JobParameterEvent(DOUBLE_PARAM));\n\t\tJobParametersEvent jobParametersEventNew = getPopulatedParametersEvent();\n\t\tassertThat(jobParametersEvent).isEqualTo(jobParametersEventNew);\n\t}\n\n\t@Test\n\tpublic void testEquals() {\n\t\tassertThat(getPopulatedParametersEvent().equals(getPopulatedParametersEvent())).isTrue();\n\t\tJobParametersEvent jobParametersEvent = getPopulatedParametersEvent();\n\t\tassertThat(jobParametersEvent.equals(\"FOO\")).isFalse();\n\t\tassertThat(jobParametersEvent.equals(jobParametersEvent)).isTrue();\n\t}\n\n\t@Test\n\tpublic void testHashCode() {\n\t\tJobParametersEvent jobParametersEvent = new JobParametersEvent();\n\t\tassertThat(jobParametersEvent.hashCode()).isNotNull();\n\t\tJobParametersEvent jobParametersEventPopulated = getPopulatedParametersEvent();\n\t\tassertThat(jobParametersEvent).isNotNull();\n\t\tassertThat(jobParametersEventPopulated.hashCode()).isNotEqualTo(jobParametersEvent.hashCode());\n\t}\n\n\t@Test\n\tpublic void testToString() {\n\t\tJobParametersEvent jobParametersEvent = getPopulatedParametersEvent();\n\t\tassertThat(toString()).isNotNull();\n\t}\n\n\tpublic JobParametersEvent getPopulatedParametersEvent() {\n\t\tSet<JobParameter<?>> jobParameters = new HashSet<>();\n\t\tjobParameters.add(DATE_PARAM);\n\t\tjobParameters.add(STRING_PARAM);\n\t\tjobParameters.add(LONG_PARAM);\n\t\tjobParameters.add(DOUBLE_PARAM);\n\t\treturn new JobParametersEvent(jobParameters);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/StepExecutionEventTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport java.time.LocalDateTime;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.batch.core.BatchStatus;\nimport org.springframework.batch.core.job.JobExecution;\nimport org.springframework.batch.core.job.JobInstance;\nimport org.springframework.batch.core.job.parameters.JobParameters;\nimport org.springframework.batch.core.step.StepExecution;\nimport org.springframework.batch.infrastructure.item.ExecutionContext;\nimport org.springframework.cloud.task.batch.listener.support.ExitStatus;\nimport org.springframework.cloud.task.batch.listener.support.StepExecutionEvent;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Glenn Renfro\n */\npublic class StepExecutionEventTests {\n\n\tprivate static final String JOB_NAME = \"FOO_JOB\";\n\n\tprivate static final String STEP_NAME = \"STEP_NAME\";\n\n\tprivate static final Long JOB_INSTANCE_ID = 1L;\n\n\tprivate static final Long JOB_EXECUTION_ID = 2L;\n\n\t@Test\n\tpublic void testBasic() {\n\t\tStepExecution stepExecution = getBasicStepExecution();\n\t\tstepExecution.setCommitCount(1);\n\t\tstepExecution.setReadCount(2);\n\t\tstepExecution.setWriteCount(3);\n\t\tstepExecution.setReadSkipCount(4);\n\t\tstepExecution.setWriteSkipCount(5);\n\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent(stepExecution);\n\t\tassertThat(stepExecutionEvent.getStepName()).as(\"stepName result was not as expected\").isEqualTo(STEP_NAME);\n\t\tassertThat(stepExecutionEvent.getStartTime()).as(\"startTime result was not as expected\")\n\t\t\t.isEqualTo(stepExecution.getStartTime());\n\t\tassertThat(stepExecutionEvent.getEndTime()).as(\"endTime result was not as expected\")\n\t\t\t.isEqualTo(stepExecution.getEndTime());\n\t\tassertThat(stepExecutionEvent.getLastUpdated()).as(\"lastUpdated result was not as expected\")\n\t\t\t.isEqualTo(stepExecution.getLastUpdated());\n\t\tassertThat(stepExecutionEvent.getCommitCount()).as(\"commitCount result was not as expected\")\n\t\t\t.isEqualTo(stepExecution.getCommitCount());\n\t\tassertThat(stepExecutionEvent.getReadCount()).as(\"readCount result was not as expected\")\n\t\t\t.isEqualTo(stepExecution.getReadCount());\n\t\tassertThat(stepExecutionEvent.getReadSkipCount()).as(\"readSkipCount result was not as expected\")\n\t\t\t.isEqualTo(stepExecution.getReadSkipCount());\n\t\tassertThat(stepExecutionEvent.getWriteCount()).as(\"writeCount result was not as expected\")\n\t\t\t.isEqualTo(stepExecution.getWriteCount());\n\t\tassertThat(stepExecutionEvent.getWriteSkipCount()).as(\"writeSkipCount result was not as expected\")\n\t\t\t.isEqualTo(stepExecution.getWriteSkipCount());\n\t\tassertThat(stepExecutionEvent.getSkipCount()).as(\"skipCount result was not as expected\")\n\t\t\t.isEqualTo(stepExecution.getSkipCount());\n\t}\n\n\t@Test\n\tpublic void testException() {\n\t\tRuntimeException exception = new RuntimeException(\"EXPECTED EXCEPTION\");\n\t\tStepExecution stepExecution = getBasicStepExecution();\n\t\tstepExecution.addFailureException(exception);\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent(stepExecution);\n\t\tassertThat(stepExecutionEvent.getFailureExceptions().size()).isEqualTo(1);\n\t\tassertThat(stepExecution.getFailureExceptions().get(0)).isEqualTo(exception);\n\t}\n\n\t@Test\n\tpublic void testGetSummary() {\n\t\tStepExecution stepExecution = getBasicStepExecution();\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent(stepExecution);\n\t\tassertThat(stepExecutionEvent.getSummary())\n\t\t\t.isEqualTo(\"StepExecutionEvent: id=2, version=null, name=STEP_NAME, status=STARTING,\"\n\t\t\t\t\t+ \" exitStatus=EXECUTING, readCount=0, filterCount=0, writeCount=0 readSkipCount=0,\"\n\t\t\t\t\t+ \" writeSkipCount=0, processSkipCount=0, commitCount=0, rollbackCount=0\");\n\t}\n\n\t@Test\n\tpublic void testHashCode() {\n\t\tStepExecution stepExecution = getBasicStepExecution();\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent(stepExecution);\n\t\tassertThat(stepExecutionEvent.toString()).isEqualTo(\"StepExecutionEvent: id=2, version=null, \"\n\t\t\t\t+ \"name=STEP_NAME, status=STARTING, exitStatus=EXECUTING, \"\n\t\t\t\t+ \"readCount=0, filterCount=0, writeCount=0 readSkipCount=0, \"\n\t\t\t\t+ \"writeSkipCount=0, processSkipCount=0, commitCount=0, \" + \"rollbackCount=0, exitDescription=\");\n\t}\n\n\t@Test\n\tpublic void testToString() {\n\t\tStepExecution stepExecution = getBasicStepExecution();\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent(stepExecution);\n\t\tassertThat(stepExecutionEvent.hashCode()).isNotNull();\n\t}\n\n\t@Test\n\tpublic void testEquals() {\n\t\tStepExecution stepExecution = getBasicStepExecution();\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent(stepExecution);\n\t\tassertThat(stepExecutionEvent.equals(getBasicStepExecution())).isFalse();\n\t}\n\n\t@Test\n\tpublic void testSettersGetters() {\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent(getBasicStepExecution());\n\t\tLocalDateTime date = LocalDateTime.now();\n\t\tstepExecutionEvent.setLastUpdated(date);\n\t\tassertThat(stepExecutionEvent.getLastUpdated()).isEqualTo(date);\n\n\t\tstepExecutionEvent.setProcessSkipCount(55);\n\t\tassertThat(stepExecutionEvent.getProcessSkipCount()).isEqualTo(55);\n\n\t\tstepExecutionEvent.setWriteSkipCount(47);\n\t\tassertThat(stepExecutionEvent.getWriteSkipCount()).isEqualTo(47);\n\n\t\tstepExecutionEvent.setReadSkipCount(49);\n\t\tassertThat(stepExecutionEvent.getReadSkipCount()).isEqualTo(49);\n\n\t\tassertThat(stepExecutionEvent.getCommitCount()).isEqualTo(0);\n\t\tstepExecutionEvent.incrementCommitCount();\n\t\tassertThat(stepExecutionEvent.getCommitCount()).isEqualTo(1);\n\n\t\tassertThat(stepExecutionEvent.isTerminateOnly()).isFalse();\n\t\tstepExecutionEvent.setTerminateOnly();\n\t\tassertThat(stepExecutionEvent.isTerminateOnly()).isTrue();\n\n\t\tstepExecutionEvent.setStepName(\"FOOBAR\");\n\t\tassertThat(stepExecutionEvent.getStepName()).isEqualTo(\"FOOBAR\");\n\n\t\tstepExecutionEvent.setStartTime(date);\n\t\tassertThat(stepExecutionEvent.getStartTime()).isEqualTo(date);\n\n\t\tassertThat(stepExecutionEvent.getRollbackCount()).isEqualTo(0);\n\t\tstepExecutionEvent.setRollbackCount(33);\n\t\tassertThat(stepExecutionEvent.getRollbackCount()).isEqualTo(33);\n\n\t\tstepExecutionEvent.setFilterCount(23);\n\t\tassertThat(stepExecutionEvent.getFilterCount()).isEqualTo(23);\n\n\t\tstepExecutionEvent.setWriteCount(11);\n\t\tassertThat(stepExecutionEvent.getWriteCount()).isEqualTo(11);\n\n\t\tstepExecutionEvent.setReadCount(12);\n\t\tassertThat(stepExecutionEvent.getReadCount()).isEqualTo(12);\n\n\t\tstepExecutionEvent.setEndTime(date);\n\t\tassertThat(stepExecutionEvent.getEndTime()).isEqualTo(date);\n\n\t\tstepExecutionEvent.setCommitCount(29);\n\t\tassertThat(stepExecutionEvent.getCommitCount()).isEqualTo(29);\n\t}\n\n\t@Test\n\tpublic void testExitStatus() {\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent(getBasicStepExecution());\n\t\tfinal String EXIT_CODE = \"1\";\n\t\tfinal String EXIT_DESCRIPTION = \"EXPECTED FAILURE\";\n\t\tExitStatus exitStatus = new ExitStatus();\n\t\texitStatus.setExitCode(EXIT_CODE);\n\t\texitStatus.setExitDescription(EXIT_DESCRIPTION);\n\n\t\tstepExecutionEvent.setExitStatus(exitStatus);\n\t\tExitStatus actualExitStatus = stepExecutionEvent.getExitStatus();\n\t\tassertThat(actualExitStatus).isNotNull();\n\t\tassertThat(actualExitStatus.getExitCode()).isEqualTo(exitStatus.getExitCode());\n\t\tassertThat(actualExitStatus.getExitDescription()).isEqualTo(exitStatus.getExitDescription());\n\t}\n\n\t@Test\n\tpublic void testBatchStatus() {\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent(getBasicStepExecution());\n\t\tassertThat(stepExecutionEvent.getStatus()).isEqualTo(BatchStatus.STARTING);\n\t\tstepExecutionEvent.setStatus(BatchStatus.ABANDONED);\n\t\tassertThat(stepExecutionEvent.getStatus()).isEqualTo(BatchStatus.ABANDONED);\n\t}\n\n\t@Test\n\tpublic void testDefaultConstructor() {\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent();\n\t\tassertThat(stepExecutionEvent.getStatus()).isEqualTo(BatchStatus.STARTING);\n\t\tassertThat(stepExecutionEvent.getExitStatus()).isNotNull();\n\t\tassertThat(stepExecutionEvent.getExitStatus().getExitCode()).isEqualTo(\"EXECUTING\");\n\t}\n\n\t@Test\n\tpublic void testExecutionContext() {\n\t\tExecutionContext executionContext = new ExecutionContext();\n\t\texecutionContext.put(\"hello\", \"world\");\n\t\tStepExecutionEvent stepExecutionEvent = new StepExecutionEvent(getBasicStepExecution());\n\t\tassertThat(stepExecutionEvent.getExecutionContext()).isNotNull();\n\t\tstepExecutionEvent.setExecutionContext(executionContext);\n\t\tassertThat(stepExecutionEvent.getExecutionContext().getString(\"hello\")).isEqualTo(\"world\");\n\t}\n\n\tprivate StepExecution getBasicStepExecution() {\n\t\tJobInstance jobInstance = new JobInstance(JOB_INSTANCE_ID, JOB_NAME);\n\t\tJobParameters jobParameters = new JobParameters();\n\t\tJobExecution jobExecution = new JobExecution(JOB_EXECUTION_ID, jobInstance, jobParameters);\n\t\treturn new StepExecution(1, STEP_NAME, jobExecution);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/TaskBatchEventListenerBeanPostProcessorTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\nimport org.springframework.batch.core.listener.ChunkListener;\nimport org.springframework.batch.core.listener.ItemProcessListener;\nimport org.springframework.batch.core.listener.ItemReadListener;\nimport org.springframework.batch.core.listener.ItemWriteListener;\nimport org.springframework.batch.core.listener.SkipListener;\nimport org.springframework.batch.core.listener.StepExecutionListener;\nimport org.springframework.batch.core.step.item.ChunkOrientedTasklet;\nimport org.springframework.batch.core.step.item.SimpleChunkProcessor;\nimport org.springframework.batch.core.step.item.SimpleChunkProvider;\nimport org.springframework.batch.core.step.tasklet.TaskletStep;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.EnableAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.cloud.task.batch.listener.support.TaskBatchEventListenerBeanPostProcessor;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.GenericApplicationContext;\nimport org.springframework.test.context.bean.override.mockito.MockitoBean;\nimport org.springframework.test.context.junit.jupiter.SpringExtension;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.mockito.Mockito.when;\n\n/**\n * @author Glenn Renfro\n */\n@ExtendWith(SpringExtension.class)\n@SpringBootTest\npublic class TaskBatchEventListenerBeanPostProcessorTests {\n\n\t@MockitoBean\n\tItemProcessListener itemProcessListener;\n\n\t@MockitoBean\n\tStepExecutionListener stepExecutionListener;\n\n\t@MockitoBean\n\tChunkListener chunkListener;\n\n\t@MockitoBean\n\tItemReadListener itemReadListener;\n\n\t@MockitoBean\n\tItemWriteListener itemWriteListener;\n\n\t@MockitoBean\n\tSkipListener skipListener;\n\n\t@MockitoBean\n\tprivate TaskletStep taskletStep;\n\n\t@MockitoBean\n\tprivate SimpleChunkProvider chunkProvider;\n\n\t@MockitoBean\n\tprivate SimpleChunkProcessor chunkProcessor;\n\n\t@Autowired\n\tprivate GenericApplicationContext context;\n\n\t@BeforeEach\n\tpublic void setupMock() {\n\t\twhen(this.taskletStep.getTasklet())\n\t\t\t\t.thenReturn(new ChunkOrientedTasklet(this.chunkProvider, this.chunkProcessor));\n\t\twhen(this.taskletStep.getName()).thenReturn(\"FOOOBAR\");\n\n\t\tregisterAlias(ItemProcessListener.class, BatchEventAutoConfiguration.ITEM_PROCESS_EVENTS_LISTENER);\n\t\tregisterAlias(StepExecutionListener.class, BatchEventAutoConfiguration.STEP_EXECUTION_EVENTS_LISTENER);\n\t\tregisterAlias(ChunkListener.class, BatchEventAutoConfiguration.CHUNK_EVENTS_LISTENER);\n\t\tregisterAlias(ItemReadListener.class, BatchEventAutoConfiguration.ITEM_READ_EVENTS_LISTENER);\n\t\tregisterAlias(ItemWriteListener.class, BatchEventAutoConfiguration.ITEM_WRITE_EVENTS_LISTENER);\n\t\tregisterAlias(SkipListener.class, BatchEventAutoConfiguration.SKIP_EVENTS_LISTENER);\n\t}\n\n\t@Test\n\tpublic void testPostProcessor() {\n\t\tTaskBatchEventListenerBeanPostProcessor postProcessor = this.context\n\t\t\t.getBean(TaskBatchEventListenerBeanPostProcessor.class);\n\t\tassertThat(postProcessor).isNotNull();\n\t\tTaskletStep updatedTaskletStep = (TaskletStep) postProcessor.postProcessBeforeInitialization(this.taskletStep,\n\t\t\t\t\"FOO\");\n\t\tassertThat(updatedTaskletStep).isEqualTo(this.taskletStep);\n\t}\n\n\tprivate void registerAlias(Class clazz, String name) {\n\t\tassertThat(this.context.getBeanNamesForType(clazz).length).isEqualTo(1);\n\t\tthis.context.registerAlias(this.context.getBeanNamesForType(clazz)[0], name);\n\n\t}\n\n\t@Configuration(proxyBeanMethods = false)\n\t@EnableAutoConfiguration\n\tpublic static class TestConfiguration {\n\n\t\t@Bean\n\t\tpublic static TaskBatchEventListenerBeanPostProcessor taskBatchEventListenerBeanPostProcessor() {\n\t\t\treturn new TaskBatchEventListenerBeanPostProcessor();\n\t\t}\n\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/support/TaskBatchEventListenerBeanPostProcessorRuntimeHintTests.java",
    "content": "/*\n * Copyright 2022-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.batch.listener.support;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.aot.hint.RuntimeHints;\nimport org.springframework.batch.core.step.item.ChunkOrientedTasklet;\nimport org.springframework.cloud.task.batch.listener.support.TaskBatchEventListenerBeanPostProcessor.RuntimeHint;\nimport org.springframework.util.ReflectionUtils;\n\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection;\n\n/**\n * @author Henning Pöttker\n */\nclass TaskBatchEventListenerBeanPostProcessorRuntimeHintTests {\n\n\tprivate RuntimeHints hints;\n\n\t@BeforeEach\n\tvoid setUp() {\n\t\tthis.hints = new RuntimeHints();\n\t\tnew RuntimeHint().registerHints(this.hints, getClass().getClassLoader());\n\t}\n\n\t@Test\n\tvoid reflectionOnChunkProviderFieldIsAllowed() {\n\t\tvar field = ReflectionUtils.findField(ChunkOrientedTasklet.class, \"chunkProvider\");\n\t\tassertThat(field).isNotNull();\n\t\tassertThat(reflection().onField(field)).accepts(this.hints);\n\t}\n\n\t@Test\n\tvoid reflectionOnChunkProcessorFieldIsAllowed() {\n\t\tvar field = ReflectionUtils.findField(ChunkOrientedTasklet.class, \"chunkProcessor\");\n\t\tassertThat(field).isNotNull();\n\t\tassertThat(reflection().onField(field)).accepts(this.hints);\n\t}\n\n}\n"
  },
  {
    "path": "spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java",
    "content": "/*\n * Copyright 2016-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage org.springframework.cloud.task.listener;\n\nimport org.junit.jupiter.api.Test;\n\nimport org.springframework.boot.WebApplicationType;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;\nimport org.springframework.cloud.task.configuration.EnableTask;\nimport org.springframework.context.ConfigurableApplicationContext;\n\nimport static org.assertj.core.api.Assertions.assertThat;\n\n/**\n * @author Michael Minella\n * @author Ilayaperumal Gopinathan\n * @author Glenn Renfro\n */\npublic class TaskEventTests {\n\n\t@Test\n\tpublic void testDefaultConfiguration() {\n\t\tConfigurableApplicationContext applicationContext = new SpringApplicationBuilder()\n\t\t\t.sources(TestChannelBinderConfiguration.getCompleteConfiguration(TaskEventsApplication.class))\n\t\t\t.web(WebApplicationType.NONE)\n\t\t\t.build()\n\t\t\t.run();\n\t\tassertThat(applicationContext.getBean(\"taskEventEmitter\")).isNotNull();\n\t}\n\n\t@EnableTask\n\t@SpringBootApplication\n\tpublic static class TaskEventsApplication {\n\n\t}\n\n}\n"
  },
  {
    "path": "src/checkstyle/checkstyle-suppressions.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE suppressions PUBLIC\n\t\t\"-//Puppy Crawl//DTD Suppressions 1.1//EN\"\n\t\t\"https://www.puppycrawl.com/dtds/suppressions_1_1.dtd\">\n<suppressions>\n\t<suppress files=\"BatchEventAutoConfiguration\\.java\" checks=\"HideUtilityClassConstructorCheck\"/>\n\t<suppress files=\"ObservationTaskAutoConfiguration\\.java\" checks=\"HideUtilityClassConstructorCheck\"/>\n\t<suppress files=\"TaskBatchAutoConfiguration\\.java\" checks=\"HideUtilityClassConstructorCheck\"/>\n</suppressions>\n"
  }
]