[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\n\ntab_width = 2\nindent_size = 2\nij_continuation_indent_size = 4\nindent_style = space\ntrim_trailing_whitespace = true\n\nij_any_blank_lines_after_imports = 2\nij_markdown_wrap_text_if_long = false\n\n\n[*.{java,kt}]\nindent_size = 4\nij_continuation_indent_size = 8\n\n\n[*.{md,mkd,markdown}]\nindent_size = 4\nij_continuation_indent_size = 8\ntrim_trailing_whitespace = false\n\n\n[*.xml]\nindent_style = tab\n\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: maven\n    directory: \"/\"\n    schedule:\n      interval: daily\n    open-pull-requests-limit: 20\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "content": "# Quickstart for GitHub Actions\n# https://docs.github.com/en/actions/quickstart\nname: fast CI\non: [ push, pull_request, workflow_dispatch ]\n\njobs:\n  test:\n    runs-on: ${{ matrix.os }}\n    timeout-minutes: 10\n    strategy:\n      matrix:\n        os: [ ubuntu-latest, windows-latest ]\n        java: [ 8, 11, 17, 21, 22 ]\n      fail-fast: false\n      max-parallel: 64\n    name: Fast CI on Java ${{ matrix.java }} OS ${{ matrix.os }}\n\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-java@v4\n        with:\n          java-version: ${{ matrix.java }}\n          distribution: zulu\n          cache: maven\n      - name: Build with Maven\n        run: ./mvnw -V --no-transfer-progress clean package\n      - name: Run unit test under ttl agent, include check for ExecutorService, ForkJoinPool, Timer/TimerTask\n        working-directory: ttl2-compatible\n        run: >\n          ../mvnw -V --no-transfer-progress\n          -Penable-ttl-agent-for-test\n          surefire:test\n          '-Dttl.agent.extra.d.options=-Drun-ttl-test-under-agent-with-enable-timer-task=true'\n      - name: Run unit test under ttl agent, and turn on the disable inheritable for thread pool enhancement\n        working-directory: ttl2-compatible\n        run: >\n          ../mvnw -V --no-transfer-progress\n          -Penable-ttl-agent-for-test\n          surefire:test\n          '-Dttl.agent.extra.args=ttl.agent.disable.inheritable.for.thread.pool:true'\n          '-Dttl.agent.extra.d.options=-Drun-ttl-test-under-agent-with-disable-inheritable=true'\n      - name: Run agent check for Timer/TimerTask, explicit \"ttl.agent.enable.timer.task\"\n        working-directory: ttl2-compatible\n        run: >\n          ../mvnw -V --no-transfer-progress\n          -Penable-ttl-agent-for-test\n          surefire:test\n          '-Dttl.agent.extra.args=ttl.agent.enable.timer.task:true'\n          '-Dttl.agent.extra.d.options=-Drun-ttl-test-under-agent-with-enable-timer-task=true'\n"
  },
  {
    "path": ".github/workflows/strong_ci.yaml",
    "content": "# Quickstart for GitHub Actions\n# https://docs.github.com/en/actions/quickstart\n\nname: Strong CI\non: [ push, pull_request, workflow_dispatch ]\njobs:\n  test:\n    # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#choosing-github-hosted-runners\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    name: Strong CI by multiply java versions\n\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: recursive\n\n      - name: Setup Java\n        uses: actions/setup-java@v4\n        with:\n          # https://github.com/actions/setup-java?tab=readme-ov-file#install-multiple-jdks\n          java-version: |\n            8\n            11\n            17\n            21\n            22\n          distribution: zulu\n          cache: maven\n\n      - name: Run integration test\n        run: scripts/integration-test.sh\n\n      - name: Remove self maven install files\n        run: rm -rf $HOME/.m2/repository/com/alibaba/{transmittable-thread-local,ttl}*\n\n      - name: Upload coverage reports to Codecov\n        uses: codecov/codecov-action@v4\n        env:\n          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}\n\n      # https://remarkablemark.org/blog/2017/10/12/check-git-dirty/\n      - name: Check git dirty\n        run: |\n          git status --short\n          [ -z \"$(git status --short)\" ]\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"scripts/bash-buddy\"]\n\tpath = scripts/bash-buddy\n\turl = https://github.com/foldright/bash-buddy.git\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.\nwrapperVersion=3.3.2\ndistributionType=only-script\ndistributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Welcome! Thank you for contributing to TransmittableThreadLocal(TTL)!\n\n> ⚠️ This contribution guide is still in progress.\n\nWe follow the standard GitHub [fork & pull](https://help.github.com/articles/using-pull-requests/#fork--pull) approach to pull requests. Just fork the official repo, develop in a branch, and submit a PR!\n\nYou're always welcome to submit your PR straight away and start the discussion (without reading the rest of this wonderful doc, or the README.md). The goal of these notes is to make your experience contributing to TransmittableThreadLocal(TTL) as smooth and pleasant as possible. We're happy to guide you through the process once you've submitted your PR.\n\n# The TransmittableThreadLocal(TTL) Community\n\nMainly use the github issue: https://github.com/alibaba/transmittable-thread-local/issues\n\nIn case of questions about the contribution process or for discussion of specific issues please visit the [alibaba/transmittable-thread-local gitter chat](https://gitter.im/alibaba/transmittable-thread-local?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge).\n\n# Navigating around the project & codebase\n\n## Branches summary\n\nDepending on what you want to work on, you should target a specific branch as explained below:\n\n* `master` – active development branch\n* `incubation/xxx` branches contain big feature.\n* `dev/xxx` branches contain small feature or bug fix.\n\n## Tags\n\nTTL uses tags to categorise issues into groups. \n\nMost notably many tags start with a `t:` prefix (as in `topic:`), which categorises issues in terms of which extension module they relate to. Examples are:\n\n- [t:vertx](https://github.com/alibaba/transmittable-thread-local/labels/t%3Avertx)\n- [t:netty](https://github.com/alibaba/transmittable-thread-local/labels/t%3Anetty)\n\nWithout `t:xxx` tags is related to `TTL` lib.\n\nsee [all tags here](https://github.com/alibaba/transmittable-thread-local/labels)\n\nIn general *all issues are open for anyone working on them*, however if you're new to the project and looking for an issue\nthat will be accepted and likely is a nice one to get started you should check out the following tags:\n\n- [good first issue](https://github.com/alibaba/transmittable-thread-local/labels/%F0%9F%94%B0%20good%20first%20issue) - which identifies simple entry level tickets, such as improvements of documentation or tests. If you're not sure how to solve a ticket but would like to work on it feel free to ask in the issue about clarification or tips.\n- [help wanted](https://github.com/alibaba/transmittable-thread-local/labels/help%20wanted) - which identifies issues that the core team will likely not have time to work on, or the issue is a nice entry level ticket. If you're not sure how to solve a ticket but would like to work on it feel free to ask in the issue about clarification or tips.\n- [nice-to-have (low-priority)](https://github.com/alibaba/transmittable-thread-local/labels/nice-to-have%20%28low-prio%29) - are tasks which make sense, however are not very high priority (in face of other very high priority issues). If you see something interesting in this list, a contribution would be really wonderful!\n\nAnother group of tickets are those which start from a number. They're used to signal in what phase of development an issue is:\n\n- [0 - new](https://github.com/alibaba/transmittable-thread-local/labels/0%20-%20new) - is assigned when a ticket is unclear on its purpose or if it is valid or not. Sometimes the additional tag `discuss` is used to mark such tickets, if they propose large scale changes and need more discussion before moving into triaged (or being closed as invalid).\n- [1 - triaged](https://github.com/alibaba/transmittable-thread-local/labels/1%20-%20triaged) - roughly speaking means \"this ticket makes sense\". Triaged tickets are safe to pick up for contributing in terms of likeliness of a patch for it being accepted. It is not recommended to start working on a ticket that is not triaged.\n- [2 - pick next](https://github.com/alibaba/transmittable-thread-local/labels/2%20-%20pick%20next) - used to mark issues which are next up in the queue to be worked on. Sometimes it's also used to mark which PRs are expected to be reviewed/merged for the next release. The tag is non-binding, and mostly used as an organisational helper.\n- [3 - in progress](https://github.com/alibaba/transmittable-thread-local/labels/3%20-%20in%20progress) - means someone is working on this ticket. If you see a ticket that has the tag, however seems inactive, it could have been an omission with removing the tag, feel free to ping the ticket then if it's still being worked on.\n\nAnother group of tags indicate type of a ticket is:\n\n- [bug](https://github.com/alibaba/transmittable-thread-local/labels/%F0%9F%90%9E%20bug) tickets indicate potential production issues. Bugs take priority in being fixed above features. The core team dedicates a number of days to working on bugs each sprint. Bugs which have **reproducers** are also great for community contributions as they're well-isolated. Sometimes we're not as lucky to have reproducers though, then a bugfix should also include a test reproducing the original error along with the fix.\n- [feature](https://github.com/alibaba/transmittable-thread-local/labels/%E2%9C%A8%20feature).\n- [enhancement](https://github.com/alibaba/transmittable-thread-local/labels/%F0%9F%92%AA%20enhancement).\n\n# TransmittableThreadLocal(TTL) contributing guidelines\n\nThese guidelines are meant to be a living document that should be changed and adapted as needed.\nWe encourage changes that make it easier to achieve our goals in an efficient way.\n\n## General workflow\n\nThe steps below describe how to get a patch into a main development branch (e.g. `master`). \nThe steps are exactly the same for everyone involved in the project (be it core team, or first time contributor).\n\n1. To avoid duplicated effort, it might be good to check the [issue tracker](https://github.com/alibaba/transmittable-thread-local/issues) and [existing pull requests](https://github.com/alibaba/transmittable-thread-local/pulls) for existing work.\n   - If there is no ticket yet, feel free to [create one](https://github.com/alibaba/transmittable-thread-local/issues/new) to discuss the problem and the approach you want to take to solve it.\n1. [Fork the project](https://github.com/alibaba/transmittable-thread-local/fork) on GitHub. You'll need to create a feature-branch for your work on your fork, as this way you'll be able to submit a pull request against the mainline.\n1. Create a branch on your fork and work on the feature. For example: `git checkout -b support-fast-thread-local`\n   - Please make sure to follow the general quality guidelines (specified below) when developing your patch.\n   - Please write additional tests covering your feature and adjust existing ones if needed before submitting your pull request. The `validatePullRequest` task ([explained below](#the-validatepullrequest-task)) may come in handy to verify your changes are correct.\n   - Use the `verifyCodeStyle` maven task to make sure your code is properly formatted and includes the proper copyright headers.\n1. Once your feature is complete, prepare the commit following our [Creating Commits And Writing Commit Messages](#creating-commits-and-writing-commit-messages). For example, a good commit message would be: `Adding compression support for Manifests #42` (note the reference to the ticket it aimed to resolve).\n1. If it's a new feature, or a change of behavior, document it on the [User Guide](https://github.com/alibaba/transmittable-thread-local/blob/master/README.md). If the feature was touching Scala or Java DSL, make sure to document both the Scala and Java APIs.\n1. Now it's finally time to [submit the pull request](https://help.github.com/articles/using-pull-requests)!\n    - Please make sure to include a reference to the issue you're solving *in the comment* for the Pull Request, as this will cause the PR to be linked properly with the Issue. Examples of good phrases for this are: \"Resolves #1234\" or \"Refs #1234\".\n1. If you have not already done so, you will be asked by our CLA bot to [sign the Alibaba CLA](https://cla-assistant.io/alibaba/transmittable-thread-local) online. CLA stands for Contributor License Agreement and is a way of protecting intellectual property disputes from harming the project.\n1. Now both committers and interested people will review your code. This process is to ensure the code we merge is of the best possible quality, and that no silly mistakes slip through. You're expected to follow-up these comments by adding new commits to the same branch. The commit messages of those commits can be more loose, for example: `Removed debugging using printline`, as they all will be squashed into one commit before merging into the main branch.\n    - The community and team are really nice people, so don't be afraid to ask follow up questions if you didn't understand some comment, or would like clarification on how to continue with a given feature. We're here to help, so feel free to ask and discuss any kind of questions you might have during review!\n1. After the review you should fix the issues as needed (pushing a new commit for new review etc.), iterating until the reviewers give their thumbs up–which is signalled usually by a comment saying `LGTM`, which means \"Looks Good To Me\".\n1. Once everything is said and done, your pull request gets merged :tada: Your feature will be available with the next “earliest” release milestone. And of course you will be given credit for the fix in the release stats during the release's announcement. You've made it!\n\nThe TL;DR; of the above very precise workflow version is:\n\n1. Fork TTL\n2. Hack and test on your feature (on a branch)\n3. Document it\n4. Submit a PR\n5. Sign the CLA if necessary\n6. Keep polishing it until received enough LGTM\n7. Profit!\n\n## Getting started with maven\n\nTTL is using the [maven](https://maven.apache.org/) build system.\n\nTo compile all the core modules use the `compile` command:\n\n```bash\n./mvnw compile\n```\n\nYou can run tests with the `test` command:\n\n```bash\n./mvnw test\n```\n\nIf you want to deploy the artifacts to your local maven repository (for example,\nto use from an maven project) use the `install` command:\n\n```bash\n./mvnw install\n```\n\n## The Pull Request validation task\n\n**TODO**\n\n## Binary compatibility\n\n**TODO**\n\n## Pull request requirements\n\nFor a pull request to be considered at all it has to meet these requirements:\n\n1. Regardless if the code introduces new features or fixes bugs or regressions, it must have comprehensive tests.\n1. The code must be well documented in the TTL project's standard documentation format (see the ‘Documentation’ section below).\n1. The commit messages must properly describe the changes, see further below.\n1. A pull request must indicate (link to) the issue it is aimed to resolve in the description (or comments) of the PR, in order to establish a link between PR and Issue. This can be achieved by writing \"Fixes #1234\" or similar in PR description.\n1. All projects must include TTL copyright notices.  Each project can choose between one of two approaches:\n\n    1. All source files in the project must have a TTL copyright notice in the file header.\n    1. The Notices file for the project includes the TTL copyright notice and no other files contain copyright notices.  See http://www.apache.org/legal/src-headers.html for instructions for managing this approach for copyrights.\n\n    TTL projects uses the first choice, having copyright notices in every file header. When absent, these are added automatically during `mvn compile`.\n\n### Additional guidelines\n\nSome additional guidelines regarding source code are:\n\n- Keep the code [DRY](http://programmer.97things.oreilly.com/wiki/index.php/Don%27t_Repeat_Yourself).\n- Apply the [Boy Scout Rule](http://programmer.97things.oreilly.com/wiki/index.php/The_Boy_Scout_Rule) whenever you have the chance to.\n- Never delete or change existing copyright notices, just add additional info.\n- Do not use ``@author`` tags since it does not encourage [Collective Code Ownership](http://www.extremeprogramming.org/rules/collective.html). TODO\n  - Contributors , each project should make sure that the contributors gets the credit they deserve—in a text file or page on the project website and in the release notes etc.\n\n## Documentation\n\nAll documentation is preferred to be in Java API doc standard documentation format, which among other things allows all code in the documentation to be externalized into compiled files and imported into the documentation.\n\nTo build the documentation locally:\n\n```\nmvn -Pgen-api-doc javadoc:javadoc\n```\n\n## Creating commits and writing commit messages\n\nFollow these guidelines when creating public commits and writing commit messages.\n\n1. If your work spans multiple local commits (for example; if you do safe point commits while working in a feature branch or work in a branch for a long time doing merges/rebases etc.) then please do not commit it all but rewrite the history by squashing the commits into a single big commit which you write a good commit message for (like discussed in the following sections). For more info read this article: [Git Workflow](http://sandofsky.com/blog/git-workflow.html). Every commit should be able to be used in isolation, cherry picked etc.\n\n2. The first line should be a descriptive sentence what the commit is doing, including the ticket number. It should be possible to fully understand what the commit does—but not necessarily how it does it—by just reading this single line. We follow the “imperative present tense” style for commit messages ([more info here](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)).\n\n   It is **not ok** to only list the ticket number, type \"minor fix\" or similar.\n   If the commit is a small fix, then you are done. If not, go to 3.\n\n3. Following the single line description should be a blank line followed by an enumerated list with the details of the commit.\n\n4. You can request review by a specific team member for your commit (depending on the degree of automation we reach, the list may change over time):\n    * ``Review by @gituser`` - if you want to notify someone on the team. The others can, and are encouraged to participate.\n\nExample:\n\n    enable Travis CI #1\n\n    * Details 1\n    * Details 2\n    * Details 3\n\n## Pull request validation workflow details\n\n**TODO**\n\n## Source style\n\nSometimes it is convenient to place 'internal' classes in their own package.\nIn such situations we prefer 'internal' over 'impl' as a package name.\n\n### Java style\n\nTTL projects uses xxx maven plugin to format Java sources.\n\n**TODO**\n\nPR validation includes checking that the Java sources are formatted and will fail if they are not.\n\n# Supporting infrastructure\n\n## Reporting security issues\n\nIf you have found an issue in an TransmittableThreadLocal(TTL) project that might have security\nimplications, you can report it to <https://security.alibaba.com>. We will make\nsure those will get handled with priority. Thank you for your responsible\ndisclosure!\n\n## Continuous integration\n\nTransmittableThreadLocal(TTL) uses GitHub actions for Continuous Integration: https://github.com/alibaba/transmittable-thread-local/actions\n\n## Related links\n\n- [alibaba/transmittable-thread-local Contributor License Agreement](https://cla-assistant.io/alibaba/transmittable-thread-local)\n- [the akka contribution guide](https://github.com/akka/akka/blob/master/CONTRIBUTING.md) (this contribution guide is adapted from it)\n"
  },
  {
    "path": "LICENSE",
    "content": "\n\n                                 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"
  },
  {
    "path": "README-EN.md",
    "content": "# <div align=\"center\"><a href=\"#dummy\"><img src=\"https://user-images.githubusercontent.com/1063891/233595946-4493119e-4e0c-4081-a382-0a20731c578e.png\" alt=\"📌 TransmittableThreadLocal(TTL)\"></a></div>\n\n> [!IMPORTANT]\n> 🚧 This branch is `TransmittableThreadLocal(TTL) v3`, which is in development and has not been released yet.  \n> See [issue 432](https://github.com/alibaba/transmittable-thread-local/issues/432) for the `v3` notes, work item list and its progress.\n>\n> 👉 The stable version `v2.x` currently in use is on [**branch `2.x`**](https://github.com/alibaba/transmittable-thread-local/tree/2.x).\n\n<p align=\"center\">\n<a href=\"https://github.com/alibaba/transmittable-thread-local/actions/workflows/ci.yaml\"><img src=\"https://img.shields.io/github/actions/workflow/status/alibaba/transmittable-thread-local/ci.yaml?branch=master&logo=github&logoColor=white&label=fast ci\" alt=\"Fast CI\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/actions/workflows/strong_ci.yaml\"><img src=\"https://img.shields.io/github/actions/workflow/status/alibaba/transmittable-thread-local/strong_ci.yaml?branch=master&logo=github&logoColor=white&label=strong ci\" alt=\"Strong CI\"></a>\n<a href=\"https://app.codecov.io/gh/alibaba/transmittable-thread-local/tree/master\"><img src=\"https://badgen.net/codecov/c/github/alibaba/transmittable-thread-local/master?icon=codecov\" alt=\"Coverage Status\"></a>\n<a href=\"https://openjdk.java.net/\"><img src=\"https://img.shields.io/badge/Java-6+-339933?logo=openjdk&logoColor=white\" alt=\"JDK support\"></a>\n<a href=\"https://www.apache.org/licenses/LICENSE-2.0.html\"><img src=\"https://img.shields.io/github/license/alibaba/transmittable-thread-local?color=4D7A97&logo=apache\" alt=\"License\"></a>\n<a href=\"https://alibaba.github.io/transmittable-thread-local/apidocs/\"><img src=\"https://img.shields.io/github/release/alibaba/transmittable-thread-local?label=javadoc&color=339933&logo=microsoft-academic&logoColor=white\" alt=\"Javadocs\"></a>\n<a href=\"https://repo1.maven.org/maven2/com/alibaba/transmittable-thread-local/maven-metadata.xml\"><img src=\"https://img.shields.io/maven-central/v/com.alibaba/transmittable-thread-local?logo=apache-maven&logoColor=white\" alt=\"Maven Central\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/releases\"><img src=\"https://img.shields.io/github/release/alibaba/transmittable-thread-local\" alt=\"GitHub release\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/stargazers\"><img src=\"https://img.shields.io/github/stars/alibaba/transmittable-thread-local?style=flat\" alt=\"GitHub Stars\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/fork\"><img src=\"https://img.shields.io/github/forks/alibaba/transmittable-thread-local?style=flat\" alt=\"GitHub Forks\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/network/dependents\"><img src=\"https://badgen.net/github/dependents-repo/alibaba/transmittable-thread-local?label=user%20repos\" alt=\"user repos\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/issues\"><img src=\"https://img.shields.io/github/issues/alibaba/transmittable-thread-local\" alt=\"GitHub issues\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/graphs/contributors\"><img src=\"https://img.shields.io/github/contributors/alibaba/transmittable-thread-local\" alt=\"GitHub Contributors\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local\"><img src=\"https://img.shields.io/github/repo-size/alibaba/transmittable-thread-local\" alt=\"GitHub repo size\"></a>\n<a href=\"https://gitpod.io/#https://github.com/alibaba/transmittable-thread-local\"><img src=\"https://img.shields.io/badge/Gitpod-ready to code-339933?label=gitpod&logo=gitpod&logoColor=white\" alt=\"gitpod: Ready to Code\"></a>\n</p>\n\n📖 English Documentation | [📖 中文文档](README.md)\n\n----------------------------------------\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n- [🔧 Functions](#-functions)\n- [🎨 Requirements](#-requirements)\n- [👥 User Guide](#-user-guide)\n    - [1. Simple usage](#1-simple-usage)\n    - [2. Transmit value even using thread pool](#2-transmit-value-even-using-thread-pool)\n        - [2.1 Decorate `Runnable` and `Callable`](#21-decorate-runnable-and-callable)\n        - [2.2 Decorate thread pool](#22-decorate-thread-pool)\n        - [2.3 Use Java Agent to decorate thread pool implementation class](#23-use-java-agent-to-decorate-thread-pool-implementation-class)\n- [🔌 Java API Docs](#-java-api-docs)\n- [🍪 Maven Dependency](#-maven-dependency)\n- [🔨 How to compile and build](#-how-to-compile-and-build)\n- [🗿 More Documentation](#-more-documentation)\n- [📚 Related Resources](#-related-resources)\n    - [JDK Core Classes](#jdk-core-classes)\n- [💗 Who Used](#-who-used)\n- [👷 Contributors](#-contributors)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n----------------------------------------\n\n# 🔧 Functions\n\n👉 `TransmittableThreadLocal`(`TTL`): The missing Java™ std lib(simple & 0-dependency) for framework/middleware,\nprovide an enhanced `InheritableThreadLocal` that transmits values between threads even using thread pooling components. Support `Java 6~21`.\n\nClass [`InheritableThreadLocal`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/InheritableThreadLocal.html) in `JDK`\ncan transmit value to child thread from parent thread.\n\nBut when use thread pool, thread is cached up and used repeatedly. Transmitting value from parent thread to child thread has no meaning.\nApplication need transmit value from the time task is created to the time task is executed.\n\nIf you have problem or question, please [submit Issue](https://github.com/alibaba/transmittable-thread-local/issues) or play [fork](https://github.com/alibaba/transmittable-thread-local/fork) and pull request dance.\n\n> [!NOTE]\n> From `TTL v2.13+` upgrade to `Java 8`. 🚀  \n> If you need `Java 6` support, use version `2.12.x` <a href=\"https://repo1.maven.org/maven2/com/alibaba/transmittable-thread-local/maven-metadata.xml\"><img src=\"https://img.shields.io/maven-central/v/com.alibaba/transmittable-thread-local?versionPrefix=2.12.&color=lightgrey&logo=apache-maven&logoColor=white\" alt=\"Maven Central\"></a>\n\n# 🎨 Requirements\n\nThe Requirements listed below is also why I sort out `TransmittableThreadLocal` in my work.\n\n- Application container or high layer framework transmit information to low layer sdk.\n- Transmit context to logging without application code aware.\n\n# 👥 User Guide\n\n## 1. Simple usage\n\n```java\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\n\n// =====================================================\n\n// set in parent thread\ncontext.set(\"value-set-in-parent\");\n\n// =====================================================\n\n// read in child thread, value is \"value-set-in-parent\"\nString value = context.get();\n```\n\n\\# See the executable demo [`SimpleDemo.kt`](ttl-core/src/test/java/com/alibaba/demo/ttl3/SimpleDemo.kt) with full source code.\n\nThis is the function of class `InheritableThreadLocal`, should use class `InheritableThreadLocal` instead.\n\nBut when use thread pool, thread is cached up and used repeatedly. Transmitting value from parent thread to child thread has no meaning.\nApplication need transmit value from the time task is created to the point task is executed.\n\nThe solution is below usage.\n\n## 2. Transmit value even using thread pool\n\n### 2.1 Decorate `Runnable` and `Callable`\n\nDecorate input `Runnable` and `Callable` by [`TtlRunnable`](ttl-core/src/main/java/com/alibaba/ttl3/TtlRunnable.java)\nand [`TtlCallable`](ttl-core/src/main/java/com/alibaba/ttl3/TtlCallable.java).\n\nSample code:\n\n```java\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\n\n// =====================================================\n\n// set in parent thread\ncontext.set(\"value-set-in-parent\");\n\nRunnable task = new RunnableTask();\n// extra work, create decorated ttlRunnable object\nRunnable ttlRunnable = TtlRunnable.get(task);\nexecutorService.submit(ttlRunnable);\n\n// =====================================================\n\n// read in task, value is \"value-set-in-parent\"\nString value = context.get();\n```\n\n**_NOTE_**：  \nEven when the same `Runnable` task is submitted to the thread pool multiple times, the decoration operations(ie： `TtlRunnable.get(task)`) is required for each submission to capture the value of the `TransmittableThreadLocal` context at submission time; That is, if the same task is submitted next time without reperforming decoration and still using the last `TtlRunnable`, the submitted task will run in the context of the last captured context. The sample code is as follows:\n\n\n```java\n// first submission\nRunnable task = new RunnableTask();\nexecutorService.submit(TtlRunnable.get(task));\n\n// ... some biz logic,\n// and modified TransmittableThreadLocal context ...\ncontext.set(\"value-modified-in-parent\");\n\n// next submission\n// reperform decoration to transmit the modified TransmittableThreadLocal context\nexecutorService.submit(TtlRunnable.get(task));\n```\n\nAbove code show how to dealing with `Runnable`, `Callable` is similar:\n\n```java\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\n\n// =====================================================\n\n// set in parent thread\ncontext.set(\"value-set-in-parent\");\n\nCallable call = new CallableTask();\n// extra work, create decorated ttlCallable object\nCallable ttlCallable = TtlCallable.get(call);\nexecutorService.submit(ttlCallable);\n\n// =====================================================\n\n// read in call, value is \"value-set-in-parent\"\nString value = context.get();\n```\n\n\\# See the executable demo [`TtlWrapperDemo.kt`](ttl-core/src/test/java/com/alibaba/demo/ttl3/TtlWrapperDemo.kt) with full source code.\n\n### 2.2 Decorate thread pool\n\nEliminating the work of `Runnable` and `Callable` Decoration every time it is submitted to thread pool. This work can be completed in the thread pool.\n\nUse util class\n[`TtlExecutors`](ttl-core/src/main/java/com/alibaba/ttl3/executor/TtlExecutors.java)\nto decorate thread pool.\n\nUtil class `TtlExecutors` has below methods:\n\n- `getTtlExecutor`: decorate interface `Executor`\n- `getTtlExecutorService`: decorate interface `ExecutorService`\n- `getTtlScheduledExecutorService`: decorate interface `ScheduledExecutorService`\n\nSample code:\n\n```java\nExecutorService executorService = ...\n// extra work, create decorated executorService object\nexecutorService = TtlExecutors.getTtlExecutorService(executorService);\n\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\n\n// =====================================================\n\n// set in parent thread\ncontext.set(\"value-set-in-parent\");\n\nRunnable task = new RunnableTask();\nCallable call = new CallableTask();\nexecutorService.submit(task);\nexecutorService.submit(call);\n\n// =====================================================\n\n// read in Task or Callable, value is \"value-set-in-parent\"\nString value = context.get();\n```\n\n\\# See the executable demo [`TtlExecutorWrapperDemo.kt`](ttl-core/src/test/java/com/alibaba/demo/ttl3/TtlExecutorWrapperDemo.kt) with full source code.\n\n### 2.3 Use Java Agent to decorate thread pool implementation class\n\nIn this usage, transmittance is transparent\\(no decoration operation\\).\n\nSample code:\n\n```java\n// ## 1. upper layer logic of framework ##\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\ncontext.set(\"value-set-in-parent\");\n\n// ## 2. biz logic ##\nExecutorService executorService = Executors.newFixedThreadPool(3);\n\nRunnable task = new RunnableTask();\nCallable call = new CallableTask();\nexecutorService.submit(task);\nexecutorService.submit(call);\n\n// ## 3. underlayer logic of framework ##\n// read in Task or Callable, value is \"value-set-in-parent\"\nString value = context.get();\n```\n\n\\# See the executable demo [`AgentDemo.kt`](ttl2-compatible/src/test/java/com/alibaba/demo/ttl/agent/AgentDemo.kt) with full source code, run demo by the script [`scripts/run-agent-demo.sh`](scripts/run-agent-demo.sh).\n\nAt present, `TTL` agent has decorated below `JDK` execution components(aka. thread pool) implementation:\n\n- `java.util.concurrent.ThreadPoolExecutor` and `java.util.concurrent.ScheduledThreadPoolExecutor`\n    - decoration implementation code is in [`JdkExecutorTtlTransformlet.java`](ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/JdkExecutorTtlTransformlet.java).\n- `java.util.concurrent.ForkJoinTask`（corresponding execution component is `java.util.concurrent.ForkJoinPool`）\n    - decoration implementation code is in [`ForkJoinTtlTransformlet.java`](ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/ForkJoinTtlTransformlet.java), supports since version **_`2.5.1`_**.\n    - **_NOTE_**: [**_`CompletableFuture`_**](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/CompletableFuture.html) and (parallel) [**_`Stream`_**](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/package-summary.html) introduced in Java 8 is executed through `ForkJoinPool` underneath, so after supporting `ForkJoinPool`, `TTL` also supports `CompletableFuture` and `Stream` transparently. 🎉\n- `java.util.TimerTask`（corresponding execution component is `java.util.Timer`）\n    - decoration implementation code is in [`TimerTaskTtlTransformlet.java`](ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/TimerTaskTtlTransformlet.java), supports since version **_`2.7.0`_**.\n    - **_NOTE_**: Since version `2.11.2` decoration for `TimerTask` default is enable (because correctness is first concern, not the best practice like \"It is not recommended to use `TimerTask`\" :); before version `2.11.1` default is disable.\n    - enabled/disable by agent argument `ttl.agent.enable.timer.task`:\n        - `-javaagent:path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:true`\n        - `-javaagent:path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:false`\n    - more info about `TTL` agent arguments, see [the javadoc of `TtlAgent.java`](ttl-agent/src/main/java/com/alibaba/ttl3/agent/TtlAgent.java).\n\nAdd start options on Java command:\n\n- `-javaagent:path/to/transmittable-thread-local-2.x.y.jar`\n\nJava command example:\n\n```bash\njava -javaagent:transmittable-thread-local-2.x.y.jar \\\n    -cp classes \\\n    com.alibaba.demo.ttl.agent.AgentDemo\n\n# if changed the TTL jar file name or the TTL version is before 2.6.0,\n# should set argument -Xbootclasspath explicitly.\njava -javaagent:path/to/ttl-foo-name-changed.jar \\\n    -Xbootclasspath/a:path/to/ttl-foo-name-changed.jar \\\n    -cp classes \\\n    com.alibaba.demo.ttl.agent.AgentDemo\n\njava -javaagent:path/to/transmittable-thread-local-2.5.1.jar \\\n    -Xbootclasspath/a:path/to/transmittable-thread-local-2.5.1.jar \\\n    -cp classes \\\n    com.alibaba.demo.ttl.agent.AgentDemo\n```\n\nRun the script [`scripts/run-agent-demo.sh`](scripts/run-agent-demo.sh)\nto start demo of \"Use Java Agent to decorate thread pool implementation class\".\n\n\n\n**NOTE**：\n\n- Because TTL agent modified the `JDK` std lib classes, make code refer from std lib class to the TTL classes, so the TTL Agent jar must be added to `boot classpath`.\n- Since `v2.6.0`, TTL agent jar will auto add self to `boot classpath`. But you **should _NOT_** modify the downloaded TTL jar file name in the maven repo(eg: `transmittable-thread-local-2.x.y.jar`).\n    - if you modified the downloaded TTL jar file name(eg: `ttl-foo-name-changed.jar`),\n      you must add TTL agent jar to `boot classpath` manually by java option `-Xbootclasspath/a:path/to/ttl-foo-name-changed.jar`.\n\nThe implementation of auto adding self agent jar to `boot classpath` use the `Boot-Class-Path` property of manifest file(`META-INF/MANIFEST.MF`) in the TTL Java Agent Jar:\n\n> [!NOTE]\n> `Boot-Class-Path`\n>\n> A list of paths to be searched by the bootstrap class loader. Paths represent directories or libraries (commonly referred to as JAR or zip libraries on many platforms).\n> These paths are searched by the bootstrap class loader after the platform specific mechanisms of locating a class have failed. Paths are searched in the order listed.\n\nMore info:\n\n- [`Java Agent Specification` - `JavaDoc`文档](https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html#package.description)\n- [JAR File Specification - JAR Manifest](https://docs.oracle.com/en/java/javase/21/docs/specs/jar/jar.html#jar-manifest)\n- [Working with Manifest Files - The Java™ Tutorials](https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html)\n\n# 🔌 Java API Docs\n\nThe current version Java API documentation: <https://alibaba.github.io/transmittable-thread-local/apidocs/>\n\n# 🍪 Maven Dependency\n\n```xml\n<dependency>\n    <groupId>com.alibaba</groupId>\n    <artifactId>transmittable-thread-local</artifactId>\n    <version>2.14.4</version>\n</dependency>\n```\n\nCheck available version at [maven.org](https://repo1.maven.org/maven2/com/alibaba/transmittable-thread-local/maven-metadata.xml).\n\n# 🔨 How to compile and build\n\nCompilation/build environment require **_`JDK 8+`_**; Compilation can be performed in the normal way of `Maven`.\n\n\\# The project already contains `Maven` that satisfied the required version, directly run **_`mvnw` in the project root directory_**; there is no need to manually install `Maven` by yourself.\n\n```bash\n# Run test case\n./mvnw test\n# Compile and package\n./mvnw package\n# Run test case, compile and package, install TTL library to local Maven\n./mvnw install\n\n##################################################\n# If you use maven installed by yourself, the version requirement: maven 3.3.9+\n\nmvn install\n```\n\n# 🗿 More Documentation\n\n- [🎓 Developer Guide](docs/developer-guide-en.md)\n\n# 📚 Related Resources\n\n## JDK Core Classes\n\n- [WeakHashMap](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/WeakHashMap.html)\n- [InheritableThreadLocal](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/InheritableThreadLocal.html)\n\n# 💗 Who Used\n\nSome open-source projects used `TTL`:\n\n- **Middleware**\n    - [`sofastack/sofa-rpc` ![](https://img.shields.io/github/stars/sofastack/sofa-rpc.svg?style=social&label=Star)](https://github.com/sofastack/sofa-rpc) [![star](https://gitee.com/sofastack/sofa-rpc/badge/star.svg?theme=gray)](https://gitee.com/sofastack/sofa-rpc)  \n      SOFARPC is a high-performance, high-extensibility, production-level Java RPC framework\n    - [`trpc-group/trpc-java` ![](https://img.shields.io/github/stars/trpc-group/trpc-java.svg?style=social&label=Star)](https://github.com/trpc-group/trpc-java)  \n      A pluggable, high-performance RPC framework written in java\n    - [`tencentmusic/supersonic` ![](https://img.shields.io/github/stars/tencentmusic/supersonic.svg?style=social&label=Star)](https://github.com/tencentmusic/supersonic)  \n      SuperSonic is an out-of-the-box yet highly extensible framework for building ChatBI\n    - [`dromara/hmily` ![](https://img.shields.io/github/stars/dromara/hmily.svg?style=social&label=Star)](https://github.com/dromara/hmily) [![star](https://gitee.com/dromara/hmily/badge/star.svg?theme=gray)](https://gitee.com/dromara/hmily)  \n      Distributed transaction solutions\n    - [`dromara/gobrs-async` ![](https://img.shields.io/github/stars/dromara/gobrs-async.svg?style=social&label=Star)](https://github.com/dromara/gobrs-async) [![star](https://gitee.com/dromara/gobrs-async/badge/star.svg?theme=gray)](https://gitee.com/dromara/gobrs-async)  \n      一款功能强大、配置灵活、带有全链路异常回调、内存优化、异常状态管理于一身的高性能异步编排框架。为企业提供在复杂应用场景下动态任务编排的能力。 针对于复杂场景下，异步线程复杂性、任务依赖性、异常状态难控制性\n    - [`dromara/dynamic-tp` ![](https://img.shields.io/github/stars/dromara/dynamic-tp.svg?style=social&label=Star)](https://github.com/dromara/dynamic-tp) [![star](https://gitee.com/dromara/dynamic-tp/badge/star.svg?theme=gray)](https://gitee.com/dromara/dynamic-tp)  \n      Lightweight dynamic threadpool, with monitoring and alarming functions, base on popular config centers (already support Nacos、Apollo、Zookeeper, can be customized through SPI)\n    - [`opengoofy/hippo4j` ![](https://img.shields.io/github/stars/opengoofy/hippo4j.svg?style=social&label=Star)](https://github.com/opengoofy/hippo4j) [![star](https://gitee.com/magestack/hippo4j/badge/star.svg?theme=gray)](https://gitee.com/magestack/hippo4j)  \n      动态线程池框架，附带监控报警功能，支持 JDK、Tomcat、Jetty、Undertow 线程池；Apache RocketMQ、Dubbo、RabbitMQ、Hystrix 消费等线程池。内置两种使用模式：轻量级依赖配置中心以及无中间件依赖版本\n    - [`siaorg/sia-gateway` ![](https://img.shields.io/github/stars/siaorg/sia-gateway.svg?style=social&label=Star)](https://github.com/siaorg/sia-gateway)  \n      microservice route gateway(zuul-plus)\n    - [`huaweicloud/Sermant` ![](https://img.shields.io/github/stars/huaweicloud/Sermant.svg?style=social&label=Star)](https://github.com/huaweicloud/Sermant)  \n      Sermant, a proxyless service mesh solution based on Javaagent\n    - [`ZTO-Express/zms` ![](https://img.shields.io/github/stars/ZTO-Express/zms.svg?style=social&label=Star)](https://github.com/ZTO-Express/zms) [![star](https://gitee.com/zto_express/zms/badge/star.svg?theme=gray)](https://gitee.com/zto_express/zms)  \n      ZTO Message Service\n    - [`lxchinesszz/tomato` ![](https://img.shields.io/github/stars/lxchinesszz/tomato.svg?style=social&label=Star)](https://github.com/lxchinesszz/tomato)  \n      一款专门为SpringBoot项目设计的幂等组件\n    - [`ytyht226/taskflow` ![](https://img.shields.io/github/stars/ytyht226/taskflow.svg?style=social&label=Star)](https://github.com/ytyht226/taskflow)  \n      一款轻量、简单易用、可灵活扩展的通用任务编排框架，基于有向无环图(DAG)的方式实现，框架提供了组件复用、同步/异步编排、条件判断、分支选择等能力，可以根据不同的业务场景对任意的业务流程进行编排\n    - [`foldright/cffu` ![](https://img.shields.io/github/stars/foldright/cffu.svg?style=social&label=star)](https://github.com/foldright/cffu)  \n      🦝 Java CompletableFuture Fu, aka. CF-Fu, pronounced \"Shifu\"; include best practice/traps guide and a tiny sidekick library to improve user experience and reduce misuse.\n    - [`tuya/connector` ![](https://img.shields.io/github/stars/tuya/connector.svg?style=social&label=Star)](https://github.com/tuya/connector)  \n      The connector framework maps cloud APIs to local APIs based on simple configurations and flexible extension mechanisms\n- **Middleware/Data Processing**\n    - [`apache/shardingsphere` ![](https://img.shields.io/github/stars/apache/shardingsphere.svg?style=social&label=Star)](https://github.com/apache/shardingsphere) [![star](https://gitee.com/Sharding-Sphere/sharding-sphere/badge/star.svg?theme=gray)](https://gitee.com/Sharding-Sphere/sharding-sphere)  \n      Ecosystem to transform any database into a distributed database system, and enhance it with sharding, elastic scaling, encryption features & more\n    - [`apache/kylin` ![](https://img.shields.io/github/stars/apache/kylin.svg?style=social&label=Star)](https://github.com/apache/kylin)  \n      A unified and powerful OLAP platform for Hadoop and Cloud.\n    - [`mybatis-flex/mybatis-flex` ![](https://img.shields.io/github/stars/mybatis-flex/mybatis-flex.svg?style=social&label=Star)](https://github.com/mybatis-flex/mybatis-flex) [![star](https://gitee.com/mybatis-flex/mybatis-flex/badge/star.svg?theme=gray)](https://gitee.com/mybatis-flex/mybatis-flex)  \n      mybatis-flex is an elegant Mybatis Enhancement Framework\n    - [`basicai/xtreme1` ![](https://img.shields.io/github/stars/basicai/xtreme1.svg?style=social&label=Star)](https://github.com/basicai/xtreme1)  \n      The Next GEN Platform for Multisensory Training Data. #3D annotation, lidar-camera annotation and image annotation tools are supported\n    - [`oceanbase/odc` ![](https://img.shields.io/github/stars/oceanbase/odc.svg?style=social&label=Star)](https://github.com/oceanbase/odc)  \n      An open-source, enterprise-grade database tool for collaborative development\n    - [`sagframe/sagacity-sqltoy` ![](https://img.shields.io/github/stars/sagframe/sagacity-sqltoy.svg?style=social&label=Star)](https://github.com/sagframe/sagacity-sqltoy)  \n      Java真正智慧的ORM框架\n    - [`dromara/stream-query` ![](https://img.shields.io/github/stars/dromara/stream-query.svg?style=social&label=Star)](https://github.com/dromara/stream-query) [![star](https://gitee.com/dromara/stream-query/badge/star.svg?theme=gray)](https://gitee.com/dromara/stream-query)  \n      允许完全摆脱Mapper的mybatis-plus体验；可以使用类似“工具类”这样的静态函数进行数据库操作\n    - [`luo-zhan/Transformer` ![](https://img.shields.io/github/stars/luo-zhan/Transformer.svg?style=social&label=Star)](https://github.com/luo-zhan/Transformer)  \n      Transformer可能是最简单，但最强大的字段转换插件，一个注解搞定任意转换，让开发变得更加丝滑\n    - [`SimonAlong/Neo` ![](https://img.shields.io/github/stars/SimonAlong/Neo.svg?style=social&label=Star)](https://github.com/SimonAlong/Neo)  \n      Orm框架：基于ActiveRecord思想开发的至简化且功能很全的Orm框架\n    - [`ppdaicorp/das` ![](https://img.shields.io/github/stars/ppdaicorp/das.svg?style=social&label=Star)](https://github.com/ppdaicorp/das)  \n      数据库访问框架(data access service)，包括数据库控制台das console，数据库客户端das client和数据库服务端das server三部分\n    - [`didi/ALITA` ![](https://img.shields.io/github/stars/didi/ALITA.svg?style=social&label=Star)](https://github.com/didi/ALITA)  \n      a layer-based data analysis tool\n    - [`didi/daedalus` ![](https://img.shields.io/github/stars/didi/daedalus.svg?style=social&label=Star)](https://github.com/didi/daedalus)  \n      实现快速创建数据构造流程，数据构造流程的可视化、线上化、持久化、标准化\n- **Middleware/Flow engine**\n    - [`dromara/liteflow` ![](https://img.shields.io/github/stars/dromara/liteflow.svg?style=social&label=Star)](https://github.com/dromara/liteflow) [![star](https://gitee.com/dromara/liteFlow/badge/star.svg?theme=gray)](https://gitee.com/dromara/liteFlow)  \n      a lightweight and practical micro-process framework\n    - [`alibaba/bulbasaur` ![](https://img.shields.io/github/stars/alibaba/bulbasaur.svg?style=social&label=Star)](https://github.com/alibaba/bulbasaur)  \n      A pluggable, scalable process engine\n- **Middleware/Log**\n    - [`dromara/TLog` ![](https://img.shields.io/github/stars/dromara/TLog.svg?style=social&label=Star)](https://github.com/dromara/TLog) [![star](https://gitee.com/dromara/TLog/badge/star.svg?theme=gray)](https://gitee.com/dromara/TLog)  \n      Lightweight distributed log label tracking framework\n    - [`fayechenlong/plumelog` ![](https://img.shields.io/github/stars/fayechenlong/plumelog.svg?style=social&label=Star)](https://github.com/fayechenlong/plumelog) [![star](https://gitee.com/plumeorg/plumelog/badge/star.svg?theme=gray)](https://gitee.com/plumeorg/plumelog)  \n      一个java分布式日志组件，支持百亿级别\n    - [`minbox-projects/minbox-logging` ![](https://img.shields.io/github/stars/minbox-projects/minbox-logging.svg?style=social&label=Star)](https://github.com/minbox-projects/minbox-logging) [![star](https://gitee.com/minbox-projects/minbox-logging/badge/star.svg?theme=gray)](https://gitee.com/minbox-projects/minbox-logging)  \n      分布式零侵入式、链路式请求日志分析框架。提供Admin端点进行采集日志、分析日志、日志告警通知、服务性能分析等。通过Admin Ui可查看实时链路日志信息、在线业务服务列表\n        - [`minbox-projects/api-boot` ![](https://img.shields.io/github/stars/minbox-projects/api-boot.svg?style=social&label=Star)](https://github.com/minbox-projects/api-boot) [![star](https://gitee.com/minbox-projects/api-boot/badge/star.svg?theme=gray)](https://gitee.com/minbox-projects/api-boot)  \n          为接口服务而生的，基于“ SpringBoot”完成扩展和自动配置，内部封装了一系列的开箱即用Starters\n    - [`ofpay/logback-mdc-ttl` ![](https://img.shields.io/github/stars/ofpay/logback-mdc-ttl.svg?style=social&label=Star)](https://github.com/ofpay/logback-mdc-ttl)  \n      logback扩展，集成transmittable-thread-local支持跨线程池的mdc跟踪\n    - [`oldratlee/log4j2-ttl-thread-context-map` ![](https://img.shields.io/github/stars/oldratlee/log4j2-ttl-thread-context-map.svg?style=social&label=Star)](https://github.com/oldratlee/log4j2-ttl-thread-context-map)  \n      Log4j2 TTL ThreadContextMap, Log4j2 extension integrated TransmittableThreadLocal to MDC\n- **Middleware/Bytecode**\n    - [`ymm-tech/easy-byte-coder` ![](https://img.shields.io/github/stars/ymm-tech/easy-byte-coder.svg?style=social&label=Star)](https://github.com/ymm-tech/easy-byte-coder)  \n      Easy-byte-coder is a non-invasive bytecode injection framework based on JVM\n- **Business service or platform application**\n    - [`OpenBankProject/OBP-API` ![](https://img.shields.io/github/stars/OpenBankProject/OBP-API.svg?style=social&label=Star)](https://github.com/OpenBankProject/OBP-API)  \n      An open source RESTful API platform for banks that supports Open Banking, XS2A and PSD2 through access to accounts, transactions, counterparties, payments, entitlements and metadata - plus a host of internal banking and management APIs\n    - [`gz-yami/mall4j` ![](https://img.shields.io/github/stars/gz-yami/mall4j.svg?style=social&label=Star)](https://github.com/gz-yami/mall4j) [![star](https://gitee.com/gz-yami/mall4j/badge/star.svg?theme=gray)](https://gitee.com/gz-yami/mall4j)  \n      电商商城 java电商商城系统 uniapp商城 多用户商城\n    - [`Joolun/JooLun-wx` ![](https://img.shields.io/github/stars/Joolun/JooLun-wx.svg?style=social&label=Star)](https://github.com/Joolun/JooLun-wx) [![star](https://gitee.com/joolun/JooLun-wx/badge/star.svg?theme=gray)](https://gitee.com/joolun/JooLun-wx)  \n      JooLun微信商城\n    - [`HummerRisk/HummerRisk` ![](https://img.shields.io/github/stars/HummerRisk/HummerRisk.svg?style=social&label=Star)](https://github.com/HummerRisk/HummerRisk)  \n      云原生安全平台，包括混合云安全治理和容器云安全检测\n    - [`XiaoMi/mone` ![](https://img.shields.io/github/stars/XiaoMi/mone.svg?style=social&label=Star)](https://github.com/XiaoMi/mone)  \n      `Mone`以微服务为核心的一站式企业协同研发平台。支持公共云、专有云和混合云多种部署形态；提供从“项目创建->开发->部署->治理->应用观测”端到端的研发全流程服务；通过云原生新技术和研发新模式，打造“双敏”，敏捷研发和敏捷组织，保障小米-中国区高复杂业务、大规模团队的敏捷研发协同，实现多倍效能提升。\n    - [`yangzongzhuan/RuoYi-Cloud` ![](https://img.shields.io/github/stars/yangzongzhuan/RuoYi-Cloud.svg?style=social&label=Star)](https://github.com/yangzongzhuan/RuoYi-Cloud) [![star](https://gitee.com/y_project/RuoYi-Cloud/badge/star.svg?theme=gray)](https://gitee.com/y_project/RuoYi-Cloud)  \n      基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统\n    - [`somowhere/albedo` ![](https://img.shields.io/github/stars/somowhere/albedo.svg?style=social&label=Star)](https://github.com/somowhere/albedo) [![star](https://gitee.com/somowhere/albedo/badge/star.svg?theme=gray)](https://gitee.com/somowhere/albedo)  \n      基于 Spring Boot 、Spring Security、Mybatis 的RBAC权限管理系统\n    - [`qwdigital/LinkWechat` ![](https://img.shields.io/github/stars/qwdigital/LinkWechat.svg?style=social&label=Star)](https://github.com/qwdigital/LinkWechat) [![star](https://gitee.com/LinkWeChat/link-wechat/badge/star.svg?theme=gray)](https://gitee.com/LinkWeChat/link-wechat)  \n      基于企业微信的开源 SCRM 系统，采用主流的 Java 微服务架构，是企业私域流量管理与营销的综合解决方案，助力企业提高客户运营效率，强化营销能力，拓展盈利空间\n    - [`fushengqian/fuint` ![](https://img.shields.io/github/stars/fushengqian/fuint.svg?style=social&label=Star)](https://github.com/fushengqian/fuint) [![star](https://gitee.com/fuint/fuint-uniapp/badge/star.svg?theme=gray)](https://gitee.com/fuint/fuint-uniapp)  \n      fuint会员营销系统是一套开源的实体店铺会员管理和营销系统\n    - [`hiparker/opsli-boot` ![](https://img.shields.io/github/stars/hiparker/opsli-boot.svg?style=social&label=Star)](https://github.com/hiparker/opsli-boot) [![star](https://gitee.com/hiparker/opsli-boot/badge/star.svg?theme=gray)](https://gitee.com/hiparker/opsli-boot)  \n      一款的低代码快速平台，零代码开发，致力于做更简洁的后台管理系统\n    - [`topiam/eiam` ![](https://img.shields.io/github/stars/topiam/eiam.svg?style=social&label=Star)](https://github.com/topiam/eiam) [![star](https://gitee.com/topiam/eiam/badge/star.svg?theme=gray)](https://gitee.com/topiam/eiam)  \n      EIAM（Employee Identity and Access Management Program）企业级开源IAM平台，实现用户全生命周期的管理、统一认证和单点登录、为数字身份安全赋能\n    - [`Newspiral/newspiral-business` ![](https://img.shields.io/github/stars/Newspiral/newspiral-business.svg?style=social&label=Star)](https://github.com/Newspiral/newspiral-business)  \n      联盟区块链底层平台\n- **Tool product**\n    - [`ssssssss-team/spider-flow` ![](https://img.shields.io/github/stars/ssssssss-team/spider-flow.svg?style=social&label=Star)](https://github.com/ssssssss-team/spider-flow) [![star](https://gitee.com/ssssssss-team/spider-flow/badge/star.svg?theme=gray)](https://gitee.com/ssssssss-team/spider-flow)  \n      新一代爬虫平台，以图形化方式定义爬虫流程，不写代码即可完成爬虫\n    - [`nekolr/slime` ![](https://img.shields.io/github/stars/nekolr/slime.svg?style=social&label=Star)](https://github.com/nekolr/slime)  \n      🍰 一个可视化的爬虫平台\n    - [`Jackson0714/PassJava-Platform` ![](https://img.shields.io/github/stars/Jackson0714/PassJava-Platform.svg?style=social&label=Star)](https://github.com/Jackson0714/PassJava-Platform)  \n      一款面试刷题的 Spring Cloud 开源系统。零碎时间利用小程序查看常见面试题，夯实Java基础。 该项目可以教会你如何搭建SpringBoot项目，Spring Cloud项目。 采用流行的技术，如 SpringBoot、MyBatis、Redis、 MySql、 MongoDB、 RabbitMQ、Elasticsearch，采用Docker容器化部署\n    - [`martin-chips/DimpleBlog` ![](https://img.shields.io/github/stars/martin-chips/DimpleBlog.svg?style=social&label=Star)](https://github.com/martin-chips/DimpleBlog)  \n      基于`SpringBoot2`搭建的个人博客系统\n    - [`zjcscut/octopus` ![](https://img.shields.io/github/stars/zjcscut/octopus.svg?style=social&label=Star)](https://github.com/zjcscut/octopus)  \n      长链接压缩为短链接的服务\n    - [`xggz/mqr` ![](https://img.shields.io/github/stars/xggz/mqr.svg?style=social&label=Star)](https://github.com/xggz/mqr) [![star](https://gitee.com/mlyai/mqr/badge/star.svg?theme=gray)](https://gitee.com/mlyai/mqr)  \n      茉莉QQ机器人（简称MQR），采用mirai的Android协议实现的QQ机器人服务，通过web控制机器人的启停和配置\n- **Test solution or tool**\n    - [`alibaba/jvm-sandbox-repeater` ![](https://img.shields.io/github/stars/alibaba/jvm-sandbox-repeater.svg?style=social&label=Star)](https://github.com/alibaba/jvm-sandbox-repeater)  \n      A Java server-side recording and playback solution based on JVM-Sandbox, 录制/回放通用解决方案\n    - [`vivo/MoonBox` ![](https://img.shields.io/github/stars/vivo/MoonBox.svg?style=social&label=Star)](https://github.com/vivo/MoonBox)  \n      Moonbox（月光宝盒）是JVM-Sandbox生态下的，基于jvm-sandbox-repeater重新开发的，一款流量回放平台产品。相较于jvm-sandbox-repeater，Moonbox功能更加丰富、数据可靠性更高，同时便于快速线上部署和使用\n    - [`alibaba/testable-mock` ![](https://img.shields.io/github/stars/alibaba/testable-mock.svg?style=social&label=Star)](https://github.com/alibaba/testable-mock)  \n      换种思路写Mock，让单元测试更简单\n    - [`shulieTech/Takin` ![](https://img.shields.io/github/stars/shulieTech/Takin.svg?style=social&label=Star)](https://github.com/shulieTech/Takin)  \n      measure online environmental performance test for full-links, Especially for microservices\n        - [`shulieTech/LinkAgent` ![](https://img.shields.io/github/stars/shulieTech/LinkAgent.svg?style=social&label=Star)](https://github.com/shulieTech/LinkAgent)  \n          a Java-based open-source agent designed to collect data and control Functions for Java applications through JVM bytecode, without modifying applications codes\n    - [`alibaba/virtual-environment` ![](https://img.shields.io/github/stars/alibaba/virtual-environment.svg?style=social&label=Star)](https://github.com/alibaba/virtual-environment)  \n      Route isolation with service sharing, 阿里测试环境服务隔离和联调机制的`Kubernetes`版实现\n- **`Spring Cloud`/`Spring Boot` microservices framework solution or scaffold**\n    - [`YunaiV/ruoyi-vue-pro` ![](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Star)](https://github.com/YunaiV/ruoyi-vue-pro)  [![star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=gray)](https://gitee.com/zhijiantianya/ruoyi-vue-pro)  \n      一套全部开源的企业级的快速开发平台。基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 微信小程序，支持 RBAC 动态权限、数据权限、SaaS 多租户、Activiti + Flowable 工作流、三方登录、支付、短信、商城等功能\n    - [`YunaiV/yudao-cloud` ![](https://img.shields.io/github/stars/YunaiV/yudao-cloud.svg?style=social&label=Star)](https://github.com/YunaiV/yudao-cloud)  [![star](https://gitee.com/zhijiantianya/yudao-cloud/badge/star.svg?theme=gray)](https://gitee.com/zhijiantianya/yudao-cloud)  \n      RuoYi-Vue 全新 Cloud 版本，优化重构所有功能。基于 Spring Cloud Alibaba + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序，支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能\n    - [`zlt2000/microservices-platform` ![](https://img.shields.io/github/stars/zlt2000/microservices-platform.svg?style=social&label=Star)](https://github.com/zlt2000/microservices-platform) [![star](https://gitee.com/zlt2000/microservices-platform/badge/star.svg?theme=gray)](https://gitee.com/zlt2000/microservices-platform)  \n      基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba并采用前后端分离的企业级微服务多租户系统架构\n    - [`dromara/lamp-cloud` ![](https://img.shields.io/github/stars/dromara/lamp-cloud.svg?style=social&label=Star)](https://github.com/zuihou/lamp-cloud) [![star](https://gitee.com/dromara/lamp-cloud/badge/star.svg?theme=gray)](https://gitee.com/dromara/lamp-cloud)  \n      基于Jdk11 + SpringCloud + SpringBoot 的微服务快速开发平台，其中的可配置的SaaS功能尤其闪耀， 具备RBAC功能、网关统一鉴权、Xss防跨站攻击、自动代码生成、多种存储系统、分布式事务、分布式定时任务等多个模块，支持多业务系统并行开发， 支持多服务并行开发，可以作为后端服务的开发脚手架\n        - [`zuihou/lamp-util` ![](https://img.shields.io/github/stars/zuihou/lamp-util.svg?style=social&label=Star)](https://github.com/zuihou/lamp-util) [![star](https://gitee.com/zuihou111/lamp-util/badge/star.svg?theme=gray)](https://gitee.com/zuihou111/lamp-util)  \n          打造一套兼顾 SpringBoot 和 SpringCloud 项目的公共工具类\n    - [`matevip/matecloud` ![](https://img.shields.io/github/stars/matevip/matecloud.svg?style=social&label=Star)](https://github.com/matevip/matecloud) [![star](https://gitee.com/matevip/matecloud/badge/star.svg?theme=gray)](https://gitee.com/matevip/matecloud)  \n      一款基于Spring Cloud Alibaba的微服务架构\n    - [`gavenwangcn/vole` ![](https://img.shields.io/github/stars/gavenwangcn/vole.svg?style=social&label=Star)](https://github.com/gavenwangcn/vole)  \n      SpringCloud Micro service business framework\n    - [`liuweijw/fw-cloud-framework` ![](https://img.shields.io/github/stars/liuweijw/fw-cloud-framework.svg?style=social&label=Star)](https://github.com/liuweijw/fw-cloud-framework) [![star](https://gitee.com/liuweijw/fw-cloud-framework/badge/star.svg?theme=gray)](https://gitee.com/liuweijw/fw-cloud-framework)  \n      基于springcloud全家桶开发分布式框架（支持oauth2认证授权、SSO登录、统一下单、微信公众号服务、Shardingdbc分库分表、常见服务监控、链路监控、异步日志、redis缓存等功能），实现基于Vue全家桶等前后端分离项目工程\n    - [`liuht777/Taroco` ![](https://img.shields.io/github/stars/liuht777/Taroco.svg?style=social&label=Star)](https://github.com/liuht777/Taroco)  \n      整合Nacos、Spring Cloud Alibaba，提供了一系列starter组件， 同时提供服务治理、服务监控、OAuth2权限认证，支持服务降级/熔断、服务权重\n    - [`mingyang66/spring-parent` ![](https://img.shields.io/github/stars/mingyang66/spring-parent.svg?style=social&label=Star)](https://github.com/mingyang66/spring-parent)  \n      数据库多数据源、Redis多数据源、日志组件、全链路日志追踪、埋点扩展点、Netty、微服务、开发基础框架支持、异常统一处理、返回值、跨域、API路由、监控等\n    - [`budwk/budwk` ![](https://img.shields.io/github/stars/budwk/budwk.svg?style=social&label=Star)](https://github.com/budwk/budwk) [![star](https://gitee.com/budwk/budwk/badge/star.svg?theme=gray)](https://gitee.com/budwk/budwk)  \n      `BudWk` 原名 [`NutzWk` ![](https://img.shields.io/github/stars/Wizzercn/NutzWk.svg?style=social&label=Star)](https://github.com/Wizzercn/NutzWk) [![star](https://gitee.com/wizzer/NutzWk/badge/star.svg?theme=gray)](https://gitee.com/wizzer/NutzWk)，基于国产框架 nutz 及 nutzboot 开发的开源Web基础项目，集权限体系、系统参数、数据字典、站内消息、定时任务、CMS、微信等最常用功能，不庞杂、不面面俱到，使其具有上手容易、开发便捷、扩展灵活等特性，特别适合各类大中小型定制化项目需求\n    - [`yinjihuan/spring-cloud` ![](https://img.shields.io/github/stars/yinjihuan/spring-cloud.svg?style=social&label=Star)](https://github.com/yinjihuan/spring-cloud)  \n      《Spring Cloud微服务-全栈技术与案例解析》和《Spring Cloud微服务 入门 实战与进阶》配套源码\n    - [`louyanfeng25/ddd-demo` ![](https://img.shields.io/github/stars/louyanfeng25/ddd-demo.svg?style=social&label=Star)](https://github.com/louyanfeng25/ddd-demo)  \n      《深入浅出DDD》讲解的演示项目，为了能够更好的理解Demo中的分层与逻辑处理，我强烈建议你配合小册来深入了解DDD\n    - [`nageoffer/12306` ![](https://img.shields.io/github/stars/nageoffer/12306.svg?style=social&label=Star)](https://github.com/nageoffer/12306)  \n      12306 铁路购票服务是与大家生活和出行相关的关键系统，包括会员、购票、订单、支付和网关等服务。\n\nmore open-source projects used `TTL`, see [![user repos](https://badgen.net/github/dependents-repo/alibaba/transmittable-thread-local?label=user%20repos)](https://github.com/alibaba/transmittable-thread-local/network/dependents)\n\n# 👷 Contributors\n\n- Jerry Lee \\<oldratlee at gmail dot com> [@oldratlee](https://github.com/oldratlee)\n- Yang Fang \\<snoop.fy at gmail dot com> [@driventokill](https://github.com/driventokill)\n- Zava Xu \\<zava.kid at gmail dot com> [@zavakid](https://github.com/zavakid)\n- wuwen \\<wuwen.55 at aliyun dot com> [@wuwen5](https://github.com/wuwen5)\n- rybalkinsd \\<yan.brikl at gmail dot com> [@rybalkinsd](https://github.com/rybalkinsd)\n- David Dai \\<351450944 at qq dot com> [@LNAmp](https://github.com/LNAmp)\n- Your name here :-)\n\n[![GitHub Contributors](https://contrib.rocks/image?repo=alibaba/transmittable-thread-local)](https://github.com/alibaba/transmittable-thread-local/graphs/contributors)\n"
  },
  {
    "path": "README.md",
    "content": "# <div align=\"center\"><a href=\"#dummy\"><img src=\"https://user-images.githubusercontent.com/1063891/233595946-4493119e-4e0c-4081-a382-0a20731c578e.png\" alt=\"📌 TransmittableThreadLocal(TTL)\"></a></div>\n\n> [!IMPORTANT]\n> 🚧 这个分支是`TransmittableThreadLocal(TTL) v3`，在开发中还没有发布。  \n> `v3`的版本说明、工作项列表及其进展，参见 [issue 432](https://github.com/alibaba/transmittable-thread-local/issues/432)。\n>\n> 👉 目前使用中的稳定发布版本`v2.x`在 [**分支`2.x`**](https://github.com/alibaba/transmittable-thread-local/tree/2.x)上。\n\n<p align=\"center\">\n<a href=\"https://github.com/alibaba/transmittable-thread-local/actions/workflows/ci.yaml\"><img src=\"https://img.shields.io/github/actions/workflow/status/alibaba/transmittable-thread-local/ci.yaml?branch=master&logo=github&logoColor=white&label=fast ci\" alt=\"Fast CI\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/actions/workflows/strong_ci.yaml\"><img src=\"https://img.shields.io/github/actions/workflow/status/alibaba/transmittable-thread-local/strong_ci.yaml?branch=master&logo=github&logoColor=white&label=strong ci\" alt=\"Strong CI\"></a>\n<a href=\"https://app.codecov.io/gh/alibaba/transmittable-thread-local/tree/master\"><img src=\"https://img.shields.io/codecov/c/github/alibaba/transmittable-thread-local/master?logo=codecov&logoColor=white\" alt=\"Coverage Status\"></a>\n<a href=\"https://openjdk.java.net/\"><img src=\"https://img.shields.io/badge/Java-6+-339933?logo=openjdk&logoColor=white\" alt=\"JDK support\"></a>\n<a href=\"https://www.apache.org/licenses/LICENSE-2.0.html\"><img src=\"https://img.shields.io/github/license/alibaba/transmittable-thread-local?color=4D7A97&logo=apache\" alt=\"License\"></a>\n<a href=\"https://alibaba.github.io/transmittable-thread-local/apidocs/\"><img src=\"https://img.shields.io/github/release/alibaba/transmittable-thread-local?label=javadoc&color=339933&logo=read-the-docs&logoColor=white\" alt=\"Javadocs\"></a>\n<a href=\"https://repo1.maven.org/maven2/com/alibaba/transmittable-thread-local/maven-metadata.xml\"><img src=\"https://img.shields.io/maven-central/v/com.alibaba/transmittable-thread-local?logo=apache-maven&logoColor=white\" alt=\"Maven Central\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/releases\"><img src=\"https://img.shields.io/github/release/alibaba/transmittable-thread-local\" alt=\"GitHub release\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/stargazers\"><img src=\"https://img.shields.io/github/stars/alibaba/transmittable-thread-local?style=flat\" alt=\"GitHub Stars\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/fork\"><img src=\"https://img.shields.io/github/forks/alibaba/transmittable-thread-local?style=flat\" alt=\"GitHub Forks\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/network/dependents\"><img src=\"https://badgen.net/github/dependents-repo/alibaba/transmittable-thread-local?label=user%20repos\" alt=\"user repos\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/issues\"><img src=\"https://img.shields.io/github/issues/alibaba/transmittable-thread-local\" alt=\"GitHub issues\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local/graphs/contributors\"><img src=\"https://img.shields.io/github/contributors/alibaba/transmittable-thread-local\" alt=\"GitHub Contributors\"></a>\n<a href=\"https://github.com/alibaba/transmittable-thread-local\"><img src=\"https://img.shields.io/github/repo-size/alibaba/transmittable-thread-local\" alt=\"GitHub repo size\"></a>\n<a href=\"https://gitpod.io/#https://github.com/alibaba/transmittable-thread-local\"><img src=\"https://img.shields.io/badge/Gitpod-ready to code-339933?label=gitpod&logo=gitpod&logoColor=white\" alt=\"gitpod: Ready to Code\"></a>\n</p>\n\n[📖 English Documentation](README-EN.md) | 📖 中文文档\n\n----------------------------------------\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n- [🔧 功能](#-%E5%8A%9F%E8%83%BD)\n- [🎨 需求场景](#-%E9%9C%80%E6%B1%82%E5%9C%BA%E6%99%AF)\n- [👥 User Guide](#-user-guide)\n    - [1. 简单使用](#1-%E7%AE%80%E5%8D%95%E4%BD%BF%E7%94%A8)\n    - [2. 保证线程池中传递值](#2-%E4%BF%9D%E8%AF%81%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%B8%AD%E4%BC%A0%E9%80%92%E5%80%BC)\n        - [2.1 修饰`Runnable`和`Callable`](#21-%E4%BF%AE%E9%A5%B0runnable%E5%92%8Ccallable)\n            - [整个过程的完整时序图](#%E6%95%B4%E4%B8%AA%E8%BF%87%E7%A8%8B%E7%9A%84%E5%AE%8C%E6%95%B4%E6%97%B6%E5%BA%8F%E5%9B%BE)\n        - [2.2 修饰线程池](#22-%E4%BF%AE%E9%A5%B0%E7%BA%BF%E7%A8%8B%E6%B1%A0)\n        - [2.3 使用`Java Agent`来修饰`JDK`线程池实现类](#23-%E4%BD%BF%E7%94%A8java-agent%E6%9D%A5%E4%BF%AE%E9%A5%B0jdk%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AE%9E%E7%8E%B0%E7%B1%BB)\n            - [`Java Agent`的启动参数配置](#java-agent%E7%9A%84%E5%90%AF%E5%8A%A8%E5%8F%82%E6%95%B0%E9%85%8D%E7%BD%AE)\n- [🔌 Java API Docs](#-java-api-docs)\n- [🍪 Maven依赖](#-maven%E4%BE%9D%E8%B5%96)\n- [🔨 关于编译构建](#-%E5%85%B3%E4%BA%8E%E7%BC%96%E8%AF%91%E6%9E%84%E5%BB%BA)\n- [❓ FAQ](#-faq)\n- [✨ 使用`TTL`的好处与必要性](#-%E4%BD%BF%E7%94%A8ttl%E7%9A%84%E5%A5%BD%E5%A4%84%E4%B8%8E%E5%BF%85%E8%A6%81%E6%80%A7)\n- [🗿 更多文档](#-%E6%9B%B4%E5%A4%9A%E6%96%87%E6%A1%A3)\n- [📚 相关资料](#-%E7%9B%B8%E5%85%B3%E8%B5%84%E6%96%99)\n    - [JDK Core Classes](#jdk-core-classes)\n- [💗 Who Used](#-who-used)\n- [👷 Contributors](#-contributors)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n----------------------------------------\n\n# 🔧 功能\n\n👉 `TransmittableThreadLocal`(`TTL`)：在使用线程池等会池化复用线程的执行组件情况下，提供`ThreadLocal`值的传递功能，解决异步执行时上下文传递的问题。一个`Java`标准库本应为框架/中间件设施开发提供的标配能力，本库功能聚焦 & 0依赖，支持`Java 6~21`。\n\n`JDK`的[`InheritableThreadLocal`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/InheritableThreadLocal.html)类可以完成父线程到子线程的值传递。但对于使用线程池等会池化复用线程的执行组件的情况，线程由线程池创建好，并且线程是池化起来反复使用的；这时父子线程关系的`ThreadLocal`值传递已经没有意义，应用需要的实际上是把 **任务提交给线程池时**的`ThreadLocal`值传递到 **任务执行时**。\n\n本库提供的[`TransmittableThreadLocal`](ttl-core/src/main/java/com/alibaba/ttl3/TransmittableThreadLocal.java)类继承并加强`InheritableThreadLocal`类，解决上述的问题，使用详见 [User Guide](#-user-guide)。\n\n\n整个`TransmittableThreadLocal`库的核心功能（用户`API`、线程池`ExecutorService`/`ForkJoinPool`/`TimerTask`及其线程工厂的`Wrapper`；开发者`API`、框架/中间件的集成`API`），只有 **_~1000 `SLOC`代码行_**，非常精小。\n\n欢迎 👏\n\n- 建议和提问，[提交 Issue](https://github.com/alibaba/transmittable-thread-local/issues/new)\n- 贡献和改进，[Fork 后提通过 Pull Request 贡献代码](https://github.com/alibaba/transmittable-thread-local/fork)\n\n> [!NOTE]\n> 从`TTL v2.13+`开始，升级到`Java 8`。🚀  \n> 如果需要`Java 6`的支持，使用版本`2.12.x` <a href=\"https://repo1.maven.org/maven2/com/alibaba/transmittable-thread-local/maven-metadata.xml\"><img src=\"https://img.shields.io/maven-central/v/com.alibaba/transmittable-thread-local?versionPrefix=2.12.&color=lightgrey&logo=apache-maven&logoColor=white\" alt=\"Maven Central\"></a>\n\n# 🎨 需求场景\n\n`ThreadLocal`的需求场景即`TransmittableThreadLocal`的潜在需求场景，如果你的业务需要『在使用线程池等会池化复用线程的执行组件情况下传递`ThreadLocal`值』则是`TransmittableThreadLocal`目标场景。\n\n下面是几个典型场景例子。\n\n1. 分布式跟踪系统 或 全链路压测（即链路打标）\n2. 日志收集记录系统上下文\n3. `Request`级`Cache`\n4. 应用容器或上层框架跨应用代码给下层`SDK`传递信息\n\n各个场景的展开说明参见子文档 [需求场景](docs/requirement-scenario.md)。\n\n# 👥 User Guide\n\n使用类[`TransmittableThreadLocal`](ttl-core/src/main/java/com/alibaba/ttl3/TransmittableThreadLocal.java)来保存值，并跨线程池传递。\n\n`TransmittableThreadLocal`继承`InheritableThreadLocal`，使用方式也类似。相比`InheritableThreadLocal`，添加了`protected`的`transmitteeValue()`方法，用于定制 **任务提交给线程池时** 的`ThreadLocal`值传递到 **任务执行时** 的传递方式，缺省是简单的赋值传递。\n\n注意：如果传递的对象（引用类型）会被修改，且没有做深拷贝（如直接传递引用或是浅拷贝），那么\n\n- 因为跨线程传递而不再有线程封闭，传递对象在多个线程之间是有共享的。\n- 与`JDK`的[`InheritableThreadLocal.childValue()`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/InheritableThreadLocal.html#childValue(T))一样，需要使用者/业务逻辑注意保证传递对象的线程安全。\n\n<blockquote>\n<details>\n\n<summary>关于<code>transmitteeValue</code>方法 的 展开说明</summary>\n<br>\n\n<p>关于构词后缀<code>er</code>与<code>ee</code>的说明：\n\n<ul>\n<li><code>transmit</code>是动词传递，<code>transmitter</code>动作的执行者/主动方，而<code>transmittee</code>动作的接收者/被动方。</li>\n<li><code>er</code>与<code>ee</code>后缀的常见词是<code>employer</code>（雇主）/<code>employee</code>（雇员）、<code>caller</code>（调用者）/<code>callee</code>（被调用者）。</li>\n</ul>\n\n</details>\n</blockquote>\n\n具体使用方式见下面的说明。\n\n## 1. 简单使用\n\n父线程给子线程传递值。\n\n示例代码：\n\n```java\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\n\n// =====================================================\n\n// 在父线程中设置\ncontext.set(\"value-set-in-parent\");\n\n// =====================================================\n\n// 在子线程中可以读取，值是\"value-set-in-parent\"\nString value = context.get();\n```\n\n\\# 完整可运行的Demo代码参见[`SimpleDemo.kt`](ttl-core/src/test/java/com/alibaba/demo/ttl3/SimpleDemo.kt)。\n\n这其实是`InheritableThreadLocal`的功能，应该使用`InheritableThreadLocal`来完成。\n\n但对于使用线程池等会池化复用线程的执行组件的情况，线程由线程池创建好，并且线程是池化起来反复使用的；这时父子线程关系的`ThreadLocal`值传递已经没有意义，应用需要的实际上是把 **任务提交给线程池时**的`ThreadLocal`值传递到 **任务执行时**。\n\n解决方法参见下面的这几种用法。\n\n## 2. 保证线程池中传递值\n\n### 2.1 修饰`Runnable`和`Callable`\n\n使用[`TtlRunnable`](ttl-core/src/main/java/com/alibaba/ttl3/TtlRunnable.java)和[`TtlCallable`](ttl-core/src/main/java/com/alibaba/ttl3/TtlCallable.java)来修饰传入线程池的`Runnable`和`Callable`。\n\n示例代码：\n\n```java\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\n\n// =====================================================\n\n// 在父线程中设置\ncontext.set(\"value-set-in-parent\");\n\nRunnable task = new RunnableTask();\n// 额外的处理，生成修饰了的对象ttlRunnable\nRunnable ttlRunnable = TtlRunnable.get(task);\nexecutorService.submit(ttlRunnable);\n\n// =====================================================\n\n// Task中可以读取，值是\"value-set-in-parent\"\nString value = context.get();\n```\n\n**_注意_**：  \n即使是同一个`Runnable`任务多次提交到线程池时，每次提交时都需要通过修饰操作（即`TtlRunnable.get(task)`）以抓取这次提交时的`TransmittableThreadLocal`上下文的值；即如果同一个任务下一次提交时不执行修饰而仍然使用上一次的`TtlRunnable`，则提交的任务运行时会是之前修饰操作所抓取的上下文。示例代码如下：\n\n```java\n// 第一次提交\nRunnable task = new RunnableTask();\nexecutorService.submit(TtlRunnable.get(task));\n\n// ...业务逻辑代码，\n// 并且修改了 TransmittableThreadLocal上下文 ...\ncontext.set(\"value-modified-in-parent\");\n\n// 再次提交\n// 重新执行修饰，以传递修改了的 TransmittableThreadLocal上下文\nexecutorService.submit(TtlRunnable.get(task));\n```\n\n上面演示了`Runnable`，`Callable`的处理类似\n\n```java\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\n\n// =====================================================\n\n// 在父线程中设置\ncontext.set(\"value-set-in-parent\");\n\nCallable call = new CallableTask();\n// 额外的处理，生成修饰了的对象ttlCallable\nCallable ttlCallable = TtlCallable.get(call);\nexecutorService.submit(ttlCallable);\n\n// =====================================================\n\n// Call中可以读取，值是\"value-set-in-parent\"\nString value = context.get();\n```\n\n\\# 完整可运行的Demo代码参见[`TtlWrapperDemo.kt`](ttl-core/src/test/java/com/alibaba/demo/ttl3/TtlWrapperDemo.kt)。\n\n#### 整个过程的完整时序图\n\n[![时序图](https://user-images.githubusercontent.com/1063891/233595980-ef7f1f8b-36cd-45b3-b55b-45f7b3d1c94f.png)](#dummy)\n\n### 2.2 修饰线程池\n\n省去每次`Runnable`和`Callable`传入线程池时的修饰，这个逻辑可以在线程池中完成。\n\n通过工具类[`TtlExecutors`](ttl-core/src/main/java/com/alibaba/ttl3/executor/TtlExecutors.java)完成，有下面的方法：\n\n- `getTtlExecutor`：修饰接口`Executor`\n- `getTtlExecutorService`：修饰接口`ExecutorService`\n- `getTtlScheduledExecutorService`：修饰接口`ScheduledExecutorService`\n\n示例代码：\n\n```java\nExecutorService executorService = ...\n// 额外的处理，生成修饰了的对象executorService\nexecutorService = TtlExecutors.getTtlExecutorService(executorService);\n\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\n\n// =====================================================\n\n// 在父线程中设置\ncontext.set(\"value-set-in-parent\");\n\nRunnable task = new RunnableTask();\nCallable call = new CallableTask();\nexecutorService.submit(task);\nexecutorService.submit(call);\n\n// =====================================================\n\n// Task或是Call中可以读取，值是\"value-set-in-parent\"\nString value = context.get();\n```\n\n\\# 完整可运行的Demo代码参见[`TtlExecutorWrapperDemo.kt`](ttl-core/src/test/java/com/alibaba/demo/ttl3/TtlExecutorWrapperDemo.kt)。\n\n### 2.3 使用`Java Agent`来修饰`JDK`线程池实现类\n\n这种方式，实现线程池的传递是透明的，业务代码中没有修饰`Runnable`或是线程池的代码。即可以做到应用代码 **无侵入**。  \n\\# 关于 **无侵入** 的更多说明参见文档[`Java Agent`方式对应用代码无侵入](docs/developer-guide.md#java-agent%E6%96%B9%E5%BC%8F%E5%AF%B9%E5%BA%94%E7%94%A8%E4%BB%A3%E7%A0%81%E6%97%A0%E4%BE%B5%E5%85%A5)。\n\n示例代码：\n\n```java\n// ## 1. 框架上层逻辑，后续流程框架调用业务 ##\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\ncontext.set(\"value-set-in-parent\");\n\n// ## 2. 应用逻辑，后续流程业务调用框架下层逻辑 ##\nExecutorService executorService = Executors.newFixedThreadPool(3);\n\nRunnable task = new RunnableTask();\nCallable call = new CallableTask();\nexecutorService.submit(task);\nexecutorService.submit(call);\n\n// ## 3. 框架下层逻辑 ##\n// Task或是Call中可以读取，值是\"value-set-in-parent\"\nString value = context.get();\n```\n\nDemo参见[`AgentDemo.kt`](ttl2-compatible/src/test/java/com/alibaba/demo/ttl/agent/AgentDemo.kt)。执行工程下的脚本[`scripts/run-agent-demo.sh`](scripts/run-agent-demo.sh)即可运行Demo。\n\n目前`TTL Agent`中，修饰了的`JDK`执行器组件（即如线程池）如下：\n\n1. `java.util.concurrent.ThreadPoolExecutor` 和 `java.util.concurrent.ScheduledThreadPoolExecutor`\n    - 修饰实现代码在[`JdkExecutorTtlTransformlet.java`](ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/JdkExecutorTtlTransformlet.java)。\n1. `java.util.concurrent.ForkJoinTask`（对应的执行器组件是`java.util.concurrent.ForkJoinPool`）\n    - 修饰实现代码在[`ForkJoinTtlTransformlet.java`](ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/ForkJoinTtlTransformlet.java)。从版本 **_`2.5.1`_** 开始支持。\n    - **_注意_**：`Java 8`引入的[**_`CompletableFuture`_**](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/CompletableFuture.html)与（并行执行的）[**_`Stream`_**](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/package-summary.html)底层是通过`ForkJoinPool`来执行，所以支持`ForkJoinPool`后，`TTL`也就透明支持了`CompletableFuture`与`Stream`。🎉\n1. `java.util.TimerTask`的子类（对应的执行器组件是`java.util.Timer`）\n    - 修饰实现代码在[`TimerTaskTtlTransformlet.java`](ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/TimerTaskTtlTransformlet.java)。从版本 **_`2.7.0`_** 开始支持。\n    - **_注意_**：从`2.11.2`版本开始缺省开启`TimerTask`的修饰（因为保证正确性是第一位，而不是最佳实践『不推荐使用`TimerTask`』:）；`2.11.1`版本及其之前的版本没有缺省开启`TimerTask`的修饰。\n    - 使用`Agent`参数`ttl.agent.enable.timer.task`开启/关闭`TimerTask`的修饰：\n        - `-javaagent:path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:true`\n        - `-javaagent:path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:false`\n    - 更多关于`TTL Agent`参数的配置说明详见[`TtlAgent.java`的JavaDoc](ttl-agent/src/main/java/com/alibaba/ttl3/agent/TtlAgent.java)。\n\n<blockquote>\n<details>\n\n<summary>关于<code>java.util.TimerTask</code>/<code>java.util.Timer</code> 的 展开说明</summary>\n<br>\n\n<p><code>Timer</code>是<code>JDK 1.3</code>的老类，不推荐使用<code>Timer</code>类。\n\n<p>推荐用<a href=\"https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/ScheduledExecutorService.html\" rel=\"nofollow\"><code>ScheduledExecutorService</code></a>。<br>\n<code>ScheduledThreadPoolExecutor</code>实现更强壮，并且功能更丰富。\n如支持配置线程池的大小（<code>Timer</code>只有一个线程）；<code>Timer</code>在<code>Runnable</code>中抛出异常会中止定时执行。更多说明参见 <a href=\"https://alibaba.github.io/Alibaba-Java-Coding-Guidelines/#concurrency\" rel=\"nofollow\">10. <strong>Mandatory</strong> Run multiple TimeTask by using ScheduledExecutorService rather than Timer because Timer will kill all running threads in case of failing to catch exceptions. - Alibaba Java Coding Guidelines</a>。</p>\n\n</details>\n</blockquote>\n\n#### `Java Agent`的启动参数配置\n\n在`Java`的启动参数加上：`-javaagent:path/to/transmittable-thread-local-2.x.y.jar`。\n\n**_注意_**：\n\n- 如果修改了下载的`TTL`的`Jar`的文件名（`transmittable-thread-local-2.x.y.jar`），则需要自己手动通过`-Xbootclasspath JVM`参数来显式配置。  \n    比如修改文件名成`ttl-foo-name-changed.jar`，则还需要加上`Java`的启动参数：`-Xbootclasspath/a:path/to/ttl-foo-name-changed.jar`。\n- 或使用`v2.6.0`之前的版本（如`v2.5.1`），则也需要自己手动通过`-Xbootclasspath JVM`参数来显式配置（就像`TTL`之前的版本的做法一样）。  \n    加上`Java`的启动参数：`-Xbootclasspath/a:path/to/transmittable-thread-local-2.5.1.jar`。\n\n`Java`命令行示例如下：\n\n```bash\njava -javaagent:path/to/transmittable-thread-local-2.x.y.jar \\\n    -cp classes \\\n    com.alibaba.demo.ttl.agent.AgentDemo\n\n# 如果修改了TTL jar文件名 或 TTL版本是 2.6.0 之前\n# 则还需要显式设置 -Xbootclasspath 参数\njava -javaagent:path/to/ttl-foo-name-changed.jar \\\n    -Xbootclasspath/a:path/to/ttl-foo-name-changed.jar \\\n    -cp classes \\\n    com.alibaba.demo.ttl.agent.AgentDemo\n\njava -javaagent:path/to/transmittable-thread-local-2.5.1.jar \\\n    -Xbootclasspath/a:path/to/transmittable-thread-local-2.5.1.jar \\\n    -cp classes \\\n    com.alibaba.demo.ttl.agent.AgentDemo\n```\n\n\n\n<blockquote>\n<details>\n\n<summary>关于<code>boot class path</code> 的 展开说明</summary>\n<br>\n\n<p>因为修饰了<code>JDK</code>标准库的类，标准库由<code>bootstrap class loader</code>加载；修饰后的<code>JDK</code>类引用了<code>TTL</code>的代码，所以<code>Java Agent</code>使用方式下<code>TTL Jar</code>文件需要配置到<code>boot class path</code>上。</p>\n\n<p><code>TTL</code>从<code>v2.6.0</code>开始，加载<code>TTL Agent</code>时会自动设置<code>TTL Jar</code>到<code>boot class path</code>上。<br>\n<strong><em>注意</em></strong>：不能修改从<code>Maven</code>库下载的<code>TTL Jar</code>文件名（形如<code>transmittable-thread-local-2.x.y.jar</code>）。\n如果修改了，则需要自己手动通过<code>-Xbootclasspath JVM</code>参数来显式配置（就像<code>TTL</code>之前的版本的做法一样）。</p>\n\n<p>自动设置<code>TTL Jar</code>到<code>boot class path</code>的实现是通过指定<code>TTL Java Agent Jar</code>文件里<code>manifest</code>文件（<code>META-INF/MANIFEST.MF</code>）的<code>Boot-Class-Path</code>属性：</p>\n\n<p><code>Boot-Class-Path</code></p>\n<p>A list of paths to be searched by the bootstrap class loader. Paths represent directories or libraries (commonly referred to as JAR or zip libraries on many platforms).\nThese paths are searched by the bootstrap class loader after the platform specific mechanisms of locating a class have failed. Paths are searched in the order listed.</p>\n\n<p>更多详见</p>\n\n<ul>\n<li><a href=\"https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html#package.description\" rel=\"nofollow\"><code>Java Agent</code>规范 - <code>JavaDoc</code></a></li>\n<li><a href=\"https://docs.oracle.com/en/java/javase/21/docs/specs/jar/jar.html#jar-manifest\" rel=\"nofollow\">JAR File Specification - JAR Manifest</a></li>\n<li><a href=\"https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html\" rel=\"nofollow\">Working with Manifest Files - The Java™ Tutorials</a></li>\n</ul>\n\n</details>\n</blockquote>\n\n# 🔌 Java API Docs\n\n当前版本的Java API文档地址： <https://alibaba.github.io/transmittable-thread-local/apidocs/>\n\n# 🍪 Maven依赖\n\n示例：\n\n```xml\n<dependency>\n    <groupId>com.alibaba</groupId>\n    <artifactId>transmittable-thread-local</artifactId>\n    <version>2.14.4</version>\n</dependency>\n```\n\n可以在 [maven.org](https://repo1.maven.org/maven2/com/alibaba/transmittable-thread-local/maven-metadata.xml) 查看可用的版本。\n\n# 🔨 关于编译构建\n\n编译构建的环境要求： **_`JDK 8+`_**；用`Maven`常规的方式执行编译构建即可：  \n\\# 在工程中已经包含了符合版本要求的`Maven`，直接运行 **_工程根目录下的`mvnw`_**；并不需要先手动自己安装好`Maven`。\n\n```bash\n# 运行测试Case\n./mvnw test\n# 编译打包\n./mvnw package\n# 运行测试Case、编译打包、安装TTL库到Maven本地\n./mvnw install\n\n#####################################################\n# 如果使用你自己安装的 maven，版本要求：maven 3.3.9+\nmvn install\n```\n\n# ❓ FAQ\n\n**_Q1. `TTL Agent`与其它`Agent`（如`Skywalking`、`Promethues`）配合使用时不生效？_**\n\n配置`TTL Agent`在最前的位置，可以避免与其它其它`Agent`配合使用时，`TTL Agent`可能的不生效问题。配置示例：\n\n```bash\njava -javaagent:path/to/transmittable-thread-local-2.x.y.jar \\\n     -javaagent:path/to/skywalking-agent.jar \\\n     -jar your-app.jar\n```\n\n原因是：\n\n- 像`Skywalking`这样的`Agent`的入口逻辑（`premain`）包含了线程池的启动。\n- 如果配置在这样的`Agent`配置在前面，到了`TTL Agent`（的`premain`）时，`TTL`需要加强的线程池类已经加载（`load`）了。\n- `TTL Agent`的`TtlTransformer`是在类加载时触发类的增强；如果类已经加载了会跳过`TTL Agent`的增强逻辑。\n\n更多讨论参见 [Issue：`TTL agent`与其他`Agent`的兼容性问题 #226](https://github.com/alibaba/transmittable-thread-local/issues/226)。\n\n**_Q2. `MacOS`下，使用`Java Agent`，可能会报`JavaLaunchHelper`的出错信息_**\n\nJDK Bug: <https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8021205>  \n可以换一个版本的`JDK`。我的开发机上`1.7.0_40`有这个问题，`1.6.0_51`、`1.7.0_45`可以运行。  \n\\# `1.7.0_45`还是有`JavaLaunchHelper`的出错信息，但不影响运行。\n\n# ✨ 使用`TTL`的好处与必要性\n\n> [!NOTE]\n> 不读这一节，并不会影响你使用`TTL`来解决你碰到的问题，可以放心跳过；读了 [User Guide](#-user-guide) 就可以快速用起来了～ 😄 这一节信息密度较高不易读。\n\n**_好处：透明且自动完成所有异步执行上下文的可定制、规范化的捕捉与传递。_**  \n这个好处也是`TransmittableThreadLocal`的目标。\n\n**_必要性：随着应用的分布式微服务化并使用各种中间件，越来越多的功能与组件会涉及不同的上下文，逻辑流程也越来越长；上下文问题实际上是个大的易错的架构问题，需要统一的对业务透明的解决方案。_**\n\n使用`ThreadLocal`作为业务上下文传递的经典技术手段在中间件、技术与业务框架中广泛大量使用。而对于生产应用，几乎一定会使用线程池等异步执行组件，以高效支撑线上大流量。但使用`ThreadLocal`及其`set/remove`的上下文传递模式，在使用线程池等异步执行组件时，存在多方面的问题：\n\n**_1. 从业务使用者角度来看_**\n\n1. **繁琐**\n   - 业务逻辑要知道：有哪些上下文；各个上下文是如何获取的。\n   - 并需要业务逻辑去一个一个地捕捉与传递。\n1. **依赖**\n    - 需要直接依赖不同`ThreadLocal`上下文各自的获取的逻辑或类。\n    - 像`RPC`的上下文（如`Dubbo`的`RpcContext`）、全链路跟踪的上下文（如`SkyWalking`的`ContextManager`）、不同业务模块中的业务流程上下文，等等。\n1. **静态（易漏）**\n    - 因为要 **_事先_** 知道有哪些上下文，如果系统出现了一个新的上下文，业务逻辑就要修改添加上新上下文传递的几行代码。也就是说因 **_系统的_** 上下文新增，**_业务的_** 逻辑就跟进要修改。\n    - 而对于业务来说，不关心系统的上下文，即往往就可能遗漏，会是线上故障了。\n    - 随着应用的分布式微服务化并使用各种中间件，越来越多的功能与组件会涉及不同的上下文，逻辑流程也越来越长；上下文问题实际上是个大的易错的架构问题，需要统一的对业务透明的解决方案。\n1. **定制性**\n    - 因为需要业务逻辑来完成捕捉与传递，业务要关注『上下文的传递方式』：直接传引用？还是拷贝传值？拷贝是深拷贝还是浅拷贝？在不同的上下文会需要不同的做法。\n    - 『上下文的传递方式』往往是 **_上下文的提供者_**（或说是业务逻辑的框架部分）才能决策处理好的；而 **_上下文的使用者_**（或说是业务逻辑的应用部分）往往不（期望）知道上下文的传递方式。这也可以理解成是 **_依赖_**，即业务逻辑 依赖/关注/实现了 系统/架构的『上下文的传递方式』。\n\n**_2. 从整体流程实现角度来看_**\n\n关注的是 **上下文传递流程的规范化**。上下文传递到了子线程要做好 **_清理_**（或更准确地说是要 **_恢复_** 成之前的上下文），需要业务逻辑去处理好。如果业务逻辑对**清理**的处理不正确，比如：\n\n- 如果清理操作漏了：\n   - 下一次执行可能是上次的，即『上下文的 **_污染_**/**_串号_**』，会导致业务逻辑错误。\n   - 『上下文的 **_泄漏_**』，会导致内存泄漏问题。\n- 如果清理操作做多了，会出现上下文 **_丢失_**。\n\n上面的问题，在业务开发中引发的`Bug`真是**屡见不鲜** ！本质原因是：**_`ThreadLocal`的`set/remove`的上下文传递模式_** 在使用线程池等异步执行组件的情况下不再是有效的。常见的典型例子：\n\n- 当线程池满了且线程池的`RejectedExecutionHandler`使用的是`CallerRunsPolicy`时，提交到线程池的任务会在提交线程中直接执行，`ThreadLocal.remove`操作**清理**提交线程的上下文导致上下文**丢失**。\n- 类似的，使用`ForkJoinPool`（包含并行执行`Stream`与`CompletableFuture`，底层使用`ForkJoinPool`）的场景，展开的`ForkJoinTask`会在任务提交线程中直接执行。同样导致上下文**丢失**。\n\n怎么设计一个『上下文传递流程』方案（即上下文的生命周期），以**保证**没有上面的问题？\n\n期望：上下文生命周期的操作从业务逻辑中分离出来。业务逻辑不涉及生命周期，就不会有业务代码如疏忽清理而引发的问题了。整个上下文的传递流程或说生命周期可以规范化成：捕捉、回放和恢复这3个操作，即[**_`CRR(capture/replay/restore)`模式_**](docs/developer-guide.md#-%E6%A1%86%E6%9E%B6%E4%B8%AD%E9%97%B4%E4%BB%B6%E9%9B%86%E6%88%90ttl%E4%BC%A0%E9%80%92)。更多讨论参见 [Issue：能在详细讲解一下`replay`、`restore`的设计理念吗？#201](https://github.com/alibaba/transmittable-thread-local/issues/201)。\n\n总结上面的说明：在生产应用（几乎一定会使用线程池等异步执行组件）中，使用`ThreadLocal`及其`set/remove`的上下文传递模式**几乎一定是有问题的**，**_只是在等一个出`Bug`的机会_**。\n\n更多`TTL`好处与必要性的展开讨论参见 [Issue：这个库带来怎样的好处和优势？ #128](https://github.com/alibaba/transmittable-thread-local/issues/128)，欢迎继续讨论 ♥️\n\n# 🗿 更多文档\n\n- [🎨 需求场景说明](docs/requirement-scenario.md)\n- [❤️ 小伙伴同学们写的`TTL`使用场景 与 设计实现解析的文章（写得都很好！） - Issue #123](https://github.com/alibaba/transmittable-thread-local/issues/123)\n- [🎓 Developer Guide](docs/developer-guide.md)\n- [☔ 性能测试](docs/performance-test.md)\n\n# 📚 相关资料\n\n## JDK Core Classes\n\n- [WeakHashMap](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/WeakHashMap.html)\n- [InheritableThreadLocal](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/InheritableThreadLocal.html)\n\n# 💗 Who Used\n\n使用了`TTL`的一部分开源项目：\n\n- **中间件**\n    - [`sofastack/sofa-rpc` ![](https://img.shields.io/github/stars/sofastack/sofa-rpc.svg?style=social&label=Star)](https://github.com/sofastack/sofa-rpc) [![star](https://gitee.com/sofastack/sofa-rpc/badge/star.svg?theme=gray)](https://gitee.com/sofastack/sofa-rpc)  \n      SOFARPC is a high-performance, high-extensibility, production-level Java RPC framework\n    - [`trpc-group/trpc-java` ![](https://img.shields.io/github/stars/trpc-group/trpc-java.svg?style=social&label=Star)](https://github.com/trpc-group/trpc-java)  \n      A pluggable, high-performance RPC framework written in java\n    - [`tencentmusic/supersonic` ![](https://img.shields.io/github/stars/tencentmusic/supersonic.svg?style=social&label=Star)](https://github.com/tencentmusic/supersonic)  \n      SuperSonic is an out-of-the-box yet highly extensible framework for building ChatBI\n    - [`dromara/hmily` ![](https://img.shields.io/github/stars/dromara/hmily.svg?style=social&label=Star)](https://github.com/dromara/hmily) [![star](https://gitee.com/dromara/hmily/badge/star.svg?theme=gray)](https://gitee.com/dromara/hmily)  \n      Distributed transaction solutions\n    - [`dromara/gobrs-async` ![](https://img.shields.io/github/stars/dromara/gobrs-async.svg?style=social&label=Star)](https://github.com/dromara/gobrs-async) [![star](https://gitee.com/dromara/gobrs-async/badge/star.svg?theme=gray)](https://gitee.com/dromara/gobrs-async)  \n      一款功能强大、配置灵活、带有全链路异常回调、内存优化、异常状态管理于一身的高性能异步编排框架。为企业提供在复杂应用场景下动态任务编排的能力。 针对于复杂场景下，异步线程复杂性、任务依赖性、异常状态难控制性\n    - [`dromara/dynamic-tp` ![](https://img.shields.io/github/stars/dromara/dynamic-tp.svg?style=social&label=Star)](https://github.com/dromara/dynamic-tp) [![star](https://gitee.com/dromara/dynamic-tp/badge/star.svg?theme=gray)](https://gitee.com/dromara/dynamic-tp)  \n      轻量级动态线程池，内置监控告警功能，支持线程池上下文传递，基于主流配置中心（已支持Nacos、Apollo，Zookeeper，可通过SPI自定义实现）\n    - [`opengoofy/hippo4j` ![](https://img.shields.io/github/stars/opengoofy/hippo4j.svg?style=social&label=Star)](https://github.com/opengoofy/hippo4j) [![star](https://gitee.com/opengoofy/hippo4j/badge/star.svg?theme=gray)](https://gitee.com/magestack/hippo4j)  \n      动态线程池框架，附带监控报警功能，支持 JDK、Tomcat、Jetty、Undertow 线程池；Apache RocketMQ、Dubbo、RabbitMQ、Hystrix 消费等线程池。内置两种使用模式：轻量级依赖配置中心以及无中间件依赖版本\n    - [`siaorg/sia-gateway` ![](https://img.shields.io/github/stars/siaorg/sia-gateway.svg?style=social&label=Star)](https://github.com/siaorg/sia-gateway)  \n      微服务路由网关（zuul-plus）\n    - [`huaweicloud/Sermant` ![](https://img.shields.io/github/stars/huaweicloud/Sermant.svg?style=social&label=Star)](https://github.com/huaweicloud/Sermant)  \n      Sermant, a proxyless service mesh solution based on Javaagent\n    - [`ZTO-Express/zms` ![](https://img.shields.io/github/stars/ZTO-Express/zms.svg?style=social&label=Star)](https://github.com/ZTO-Express/zms) [![star](https://gitee.com/zto_express/zms/badge/star.svg?theme=gray)](https://gitee.com/zto_express/zms)  \n      ZTO Message Service\n    - [`lxchinesszz/tomato` ![](https://img.shields.io/github/stars/lxchinesszz/tomato.svg?style=social&label=Star)](https://github.com/lxchinesszz/tomato)  \n      一款专门为SpringBoot项目设计的幂等组件\n    - [`ytyht226/taskflow` ![](https://img.shields.io/github/stars/ytyht226/taskflow.svg?style=social&label=Star)](https://github.com/ytyht226/taskflow)  \n      一款轻量、简单易用、可灵活扩展的通用任务编排框架，基于有向无环图(DAG)的方式实现，框架提供了组件复用、同步/异步编排、条件判断、分支选择等能力，可以根据不同的业务场景对任意的业务流程进行编排\n    - [`foldright/cffu` ![](https://img.shields.io/github/stars/foldright/cffu.svg?style=social&label=star)](https://github.com/foldright/cffu)  \n      🦝 Java CompletableFuture Fu, aka. CF-Fu, pronounced \"Shifu\"; include best practice/traps guide and a tiny sidekick library to improve user experience and reduce misuse.\n    - [`tuya/connector` ![](https://img.shields.io/github/stars/tuya/connector.svg?style=social&label=Star)](https://github.com/tuya/connector)  \n      The connector framework maps cloud APIs to local APIs based on simple configurations and flexible extension mechanisms\n- **中间件/数据处理**\n    - [`apache/shardingsphere` ![](https://img.shields.io/github/stars/apache/shardingsphere.svg?style=social&label=Star)](https://github.com/apache/shardingsphere) [![star](https://gitee.com/Sharding-Sphere/sharding-sphere/badge/star.svg?theme=gray)](https://gitee.com/Sharding-Sphere/sharding-sphere)  \n      Ecosystem to transform any database into a distributed database system, and enhance it with sharding, elastic scaling, encryption features & more\n    - [`apache/kylin` ![](https://img.shields.io/github/stars/apache/kylin.svg?style=social&label=Star)](https://github.com/apache/kylin)  \n      A unified and powerful OLAP platform for Hadoop and Cloud.\n    - [`mybatis-flex/mybatis-flex` ![](https://img.shields.io/github/stars/mybatis-flex/mybatis-flex.svg?style=social&label=Star)](https://github.com/mybatis-flex/mybatis-flex) [![star](https://gitee.com/mybatis-flex/mybatis-flex/badge/star.svg?theme=gray)](https://gitee.com/mybatis-flex/mybatis-flex)  \n      mybatis-flex is an elegant Mybatis Enhancement Framework\n    - [`basicai/xtreme1` ![](https://img.shields.io/github/stars/basicai/xtreme1.svg?style=social&label=Star)](https://github.com/basicai/xtreme1)  \n      The Next GEN Platform for Multisensory Training Data. #3D annotation, lidar-camera annotation and image annotation tools are supported\n    - [`oceanbase/odc` ![](https://img.shields.io/github/stars/oceanbase/odc.svg?style=social&label=Star)](https://github.com/oceanbase/odc)  \n      An open-source, enterprise-grade database tool for collaborative development\n    - [`sagframe/sagacity-sqltoy` ![](https://img.shields.io/github/stars/sagframe/sagacity-sqltoy.svg?style=social&label=Star)](https://github.com/sagframe/sagacity-sqltoy)  \n      Java真正智慧的ORM框架\n    - [`dromara/stream-query` ![](https://img.shields.io/github/stars/dromara/stream-query.svg?style=social&label=Star)](https://github.com/dromara/stream-query) [![star](https://gitee.com/dromara/stream-query/badge/star.svg?theme=gray)](https://gitee.com/dromara/stream-query)  \n      允许完全摆脱Mapper的mybatis-plus体验；可以使用类似“工具类”这样的静态函数进行数据库操作\n    - [`luo-zhan/Transformer` ![](https://img.shields.io/github/stars/luo-zhan/Transformer.svg?style=social&label=Star)](https://github.com/luo-zhan/Transformer)  \n      Transformer可能是最简单，但最强大的字段转换插件，一个注解搞定任意转换，让开发变得更加丝滑\n    - [`SimonAlong/Neo` ![](https://img.shields.io/github/stars/SimonAlong/Neo.svg?style=social&label=Star)](https://github.com/SimonAlong/Neo)  \n      Orm框架：基于ActiveRecord思想开发的至简化且功能很全的Orm框架\n    - [`ppdaicorp/das` ![](https://img.shields.io/github/stars/ppdaicorp/das.svg?style=social&label=Star)](https://github.com/ppdaicorp/das)  \n      数据库访问框架(data access service)，包括数据库控制台das console，数据库客户端das client和数据库服务端das server三部分\n    - [`didi/ALITA` ![](https://img.shields.io/github/stars/didi/ALITA.svg?style=social&label=Star)](https://github.com/didi/ALITA)  \n      a layer-based data analysis tool\n    - [`didi/daedalus` ![](https://img.shields.io/github/stars/didi/daedalus.svg?style=social&label=Star)](https://github.com/didi/daedalus)  \n      实现快速创建数据构造流程，数据构造流程的可视化、线上化、持久化、标准化\n- **中间件/流程引擎**\n    - [`dromara/liteflow` ![](https://img.shields.io/github/stars/dromara/liteflow.svg?style=social&label=Star)](https://github.com/dromara/liteflow) [![star](https://gitee.com/dromara/liteFlow/badge/star.svg?theme=gray)](https://gitee.com/dromara/liteFlow)  \n      a lightweight and practical micro-process framework\n    - [`alibaba/bulbasaur` ![](https://img.shields.io/github/stars/alibaba/bulbasaur.svg?style=social&label=Star)](https://github.com/alibaba/bulbasaur)  \n      A pluggable, scalable process engine\n- **中间件/日志**\n    - [`dromara/TLog` ![](https://img.shields.io/github/stars/dromara/TLog.svg?style=social&label=Star)](https://github.com/dromara/TLog) [![star](https://gitee.com/dromara/TLog/badge/star.svg?theme=gray)](https://gitee.com/dromara/TLog)  \n      Lightweight distributed log label tracking framework\n    - [`fayechenlong/plumelog` ![](https://img.shields.io/github/stars/fayechenlong/plumelog.svg?style=social&label=Star)](https://github.com/fayechenlong/plumelog) [![star](https://gitee.com/plumeorg/plumelog/badge/star.svg?theme=gray)](https://gitee.com/plumeorg/plumelog)  \n      一个java分布式日志组件，支持百亿级别\n    - [`minbox-projects/minbox-logging` ![](https://img.shields.io/github/stars/minbox-projects/minbox-logging.svg?style=social&label=Star)](https://github.com/minbox-projects/minbox-logging) [![star](https://gitee.com/minbox-projects/minbox-logging/badge/star.svg?theme=gray)](https://gitee.com/minbox-projects/minbox-logging)  \n      分布式零侵入式、链路式请求日志分析框架。提供Admin端点进行采集日志、分析日志、日志告警通知、服务性能分析等。通过Admin Ui可查看实时链路日志信息、在线业务服务列表\n        - [`minbox-projects/api-boot` ![](https://img.shields.io/github/stars/minbox-projects/api-boot.svg?style=social&label=Star)](https://github.com/minbox-projects/api-boot) [![star](https://gitee.com/minbox-projects/api-boot/badge/star.svg?theme=gray)](https://gitee.com/minbox-projects/api-boot)  \n          为接口服务而生的，基于“ SpringBoot”完成扩展和自动配置，内部封装了一系列的开箱即用Starters\n    - [`ofpay/logback-mdc-ttl` ![](https://img.shields.io/github/stars/ofpay/logback-mdc-ttl.svg?style=social&label=Star)](https://github.com/ofpay/logback-mdc-ttl)  \n      logback扩展，集成transmittable-thread-local支持跨线程池的mdc跟踪\n    - [`oldratlee/log4j2-ttl-thread-context-map` ![](https://img.shields.io/github/stars/oldratlee/log4j2-ttl-thread-context-map.svg?style=social&label=Star)](https://github.com/oldratlee/log4j2-ttl-thread-context-map)  \n      Log4j2 TTL ThreadContextMap, Log4j2 extension integrated TransmittableThreadLocal to MDC\n    - [`qqxx6661/log-record` ![](https://img.shields.io/github/stars/qqxx6661/log-record.svg?style=social&label=Star)](https://github.com/qqxx6661/log-record)\n      业务日志记录框架，使用注解优雅记录日志，支持SpEL表达式，自定义上下文，自定义函数，实体类DIFF等特性。\n- **中间件/字节码**\n    - [`ymm-tech/easy-byte-coder` ![](https://img.shields.io/github/stars/ymm-tech/easy-byte-coder.svg?style=social&label=Star)](https://github.com/ymm-tech/easy-byte-coder)  \n      Easy-byte-coder is a non-invasive bytecode injection framework based on JVM\n- **业务服务或平台应用**\n    - [`OpenBankProject/OBP-API` ![](https://img.shields.io/github/stars/OpenBankProject/OBP-API.svg?style=social&label=Star)](https://github.com/OpenBankProject/OBP-API)  \n      An open source RESTful API platform for banks that supports Open Banking, XS2A and PSD2 through access to accounts, transactions, counterparties, payments, entitlements and metadata - plus a host of internal banking and management APIs\n    - [`gz-yami/mall4j` ![](https://img.shields.io/github/stars/gz-yami/mall4j.svg?style=social&label=Star)](https://github.com/gz-yami/mall4j) [![star](https://gitee.com/gz-yami/mall4j/badge/star.svg?theme=gray)](https://gitee.com/gz-yami/mall4j)  \n      电商商城 java电商商城系统 uniapp商城 多用户商城\n    - [`Joolun/JooLun-wx` ![](https://img.shields.io/github/stars/Joolun/JooLun-wx.svg?style=social&label=Star)](https://github.com/Joolun/JooLun-wx) [![star](https://gitee.com/joolun/JooLun-wx/badge/star.svg?theme=gray)](https://gitee.com/joolun/JooLun-wx)  \n      JooLun微信商城\n    - [`HummerRisk/HummerRisk` ![](https://img.shields.io/github/stars/HummerRisk/HummerRisk.svg?style=social&label=Star)](https://github.com/HummerRisk/HummerRisk)  \n      云原生安全平台，包括混合云安全治理和容器云安全检测\n    - [`XiaoMi/mone` ![](https://img.shields.io/github/stars/XiaoMi/mone.svg?style=social&label=Star)](https://github.com/XiaoMi/mone)  \n      `Mone`以微服务为核心的一站式企业协同研发平台。支持公共云、专有云和混合云多种部署形态；提供从“项目创建->开发->部署->治理->应用观测”端到端的研发全流程服务；通过云原生新技术和研发新模式，打造“双敏”，敏捷研发和敏捷组织，保障小米-中国区高复杂业务、大规模团队的敏捷研发协同，实现多倍效能提升。\n    - [`yangzongzhuan/RuoYi-Cloud` ![](https://img.shields.io/github/stars/yangzongzhuan/RuoYi-Cloud.svg?style=social&label=Star)](https://github.com/yangzongzhuan/RuoYi-Cloud) [![star](https://gitee.com/y_project/RuoYi-Cloud/badge/star.svg?theme=gray)](https://gitee.com/y_project/RuoYi-Cloud)  \n      基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统\n    - [`somowhere/albedo` ![](https://img.shields.io/github/stars/somowhere/albedo.svg?style=social&label=Star)](https://github.com/somowhere/albedo) [![star](https://gitee.com/somowhere/albedo/badge/star.svg?theme=gray)](https://gitee.com/somowhere/albedo)  \n      基于 Spring Boot 、Spring Security、Mybatis 的RBAC权限管理系统\n    - [`qwdigital/LinkWechat` ![](https://img.shields.io/github/stars/qwdigital/LinkWechat.svg?style=social&label=Star)](https://github.com/qwdigital/LinkWechat) [![star](https://gitee.com/LinkWeChat/link-wechat/badge/star.svg?theme=gray)](https://gitee.com/LinkWeChat/link-wechat)  \n      基于企业微信的开源 SCRM 系统，采用主流的 Java 微服务架构，是企业私域流量管理与营销的综合解决方案，助力企业提高客户运营效率，强化营销能力，拓展盈利空间\n    - [`fushengqian/fuint` ![](https://img.shields.io/github/stars/fushengqian/fuint.svg?style=social&label=Star)](https://github.com/fushengqian/fuint) [![star](https://gitee.com/fuint/fuint-uniapp/badge/star.svg?theme=gray)](https://gitee.com/fuint/fuint-uniapp)  \n      fuint会员营销系统是一套开源的实体店铺会员管理和营销系统\n    - [`hiparker/opsli-boot` ![](https://img.shields.io/github/stars/hiparker/opsli-boot.svg?style=social&label=Star)](https://github.com/hiparker/opsli-boot) [![star](https://gitee.com/hiparker/opsli-boot/badge/star.svg?theme=gray)](https://gitee.com/hiparker/opsli-boot)  \n      一款的低代码快速平台，零代码开发，致力于做更简洁的后台管理系统\n    - [`topiam/eiam` ![](https://img.shields.io/github/stars/topiam/eiam.svg?style=social&label=Star)](https://github.com/topiam/eiam) [![star](https://gitee.com/topiam/eiam/badge/star.svg?theme=gray)](https://gitee.com/topiam/eiam)  \n      EIAM（Employee Identity and Access Management Program）企业级开源IAM平台，实现用户全生命周期的管理、统一认证和单点登录、为数字身份安全赋能\n    - [`Newspiral/newspiral-business` ![](https://img.shields.io/github/stars/Newspiral/newspiral-business.svg?style=social&label=Star)](https://github.com/Newspiral/newspiral-business)  \n      联盟区块链底层平台\n- **工具产品**\n    - [`ssssssss-team/spider-flow` ![](https://img.shields.io/github/stars/ssssssss-team/spider-flow.svg?style=social&label=Star)](https://github.com/ssssssss-team/spider-flow) [![star](https://gitee.com/ssssssss-team/spider-flow/badge/star.svg?theme=gray)](https://gitee.com/ssssssss-team/spider-flow)  \n      新一代爬虫平台，以图形化方式定义爬虫流程，不写代码即可完成爬虫\n    - [`nekolr/slime` ![](https://img.shields.io/github/stars/nekolr/slime.svg?style=social&label=Star)](https://github.com/nekolr/slime)  \n      🍰 一个可视化的爬虫平台\n    - [`Jackson0714/PassJava-Platform` ![](https://img.shields.io/github/stars/Jackson0714/PassJava-Platform.svg?style=social&label=Star)](https://github.com/Jackson0714/PassJava-Platform)  \n      一款面试刷题的 Spring Cloud 开源系统。零碎时间利用小程序查看常见面试题，夯实Java基础。 该项目可以教会你如何搭建SpringBoot项目，Spring Cloud项目。 采用流行的技术，如 SpringBoot、MyBatis、Redis、 MySql、 MongoDB、 RabbitMQ、Elasticsearch，采用Docker容器化部署\n    - [`martin-chips/DimpleBlog` ![](https://img.shields.io/github/stars/martin-chips/DimpleBlog.svg?style=social&label=Star)](https://github.com/martin-chips/DimpleBlog)  \n      基于`SpringBoot2`搭建的个人博客系统\n    - [`zjcscut/octopus` ![](https://img.shields.io/github/stars/zjcscut/octopus.svg?style=social&label=Star)](https://github.com/zjcscut/octopus)  \n      长链接压缩为短链接的服务\n    - [`xggz/mqr` ![](https://img.shields.io/github/stars/xggz/mqr.svg?style=social&label=Star)](https://github.com/xggz/mqr) [![star](https://gitee.com/mlyai/mqr/badge/star.svg?theme=gray)](https://gitee.com/mlyai/mqr)  \n      茉莉QQ机器人（简称MQR），采用mirai的Android协议实现的QQ机器人服务，通过web控制机器人的启停和配置\n- **测试解决方案或工具**\n    - [`alibaba/jvm-sandbox-repeater` ![](https://img.shields.io/github/stars/alibaba/jvm-sandbox-repeater.svg?style=social&label=Star)](https://github.com/alibaba/jvm-sandbox-repeater)  \n      A Java server-side recording and playback solution based on JVM-Sandbox, 录制/回放通用解决方案\n    - [`vivo/MoonBox` ![](https://img.shields.io/github/stars/vivo/MoonBox.svg?style=social&label=Star)](https://github.com/vivo/MoonBox)  \n      Moonbox（月光宝盒）是JVM-Sandbox生态下的，基于jvm-sandbox-repeater重新开发的，一款流量回放平台产品。相较于jvm-sandbox-repeater，Moonbox功能更加丰富、数据可靠性更高，同时便于快速线上部署和使用\n    - [`alibaba/testable-mock` ![](https://img.shields.io/github/stars/alibaba/testable-mock.svg?style=social&label=Star)](https://github.com/alibaba/testable-mock)  \n      换种思路写Mock，让单元测试更简单\n    - [`shulieTech/Takin` ![](https://img.shields.io/github/stars/shulieTech/Takin.svg?style=social&label=Star)](https://github.com/shulieTech/Takin)  \n      全链路压测平台，measure online environmental performance test for full-links, Especially for microservices\n        - [`shulieTech/LinkAgent` ![](https://img.shields.io/github/stars/shulieTech/LinkAgent.svg?style=social&label=Star)](https://github.com/shulieTech/LinkAgent)  \n          a Java-based open-source agent designed to collect data and control Functions for Java applications through JVM bytecode, without modifying applications codes\n    - [`alibaba/virtual-environment` ![](https://img.shields.io/github/stars/alibaba/virtual-environment.svg?style=social&label=Star)](https://github.com/alibaba/virtual-environment)  \n      Route isolation with service sharing, 阿里测试环境服务隔离和联调机制的`Kubernetes`版实现\n- **`Spring Cloud`/`Spring Boot`的框架方案/脚手架**\n    - [`YunaiV/ruoyi-vue-pro` ![](https://img.shields.io/github/stars/YunaiV/ruoyi-vue-pro.svg?style=social&label=Star)](https://github.com/YunaiV/ruoyi-vue-pro)  [![star](https://gitee.com/zhijiantianya/ruoyi-vue-pro/badge/star.svg?theme=gray)](https://gitee.com/zhijiantianya/ruoyi-vue-pro)  \n      一套全部开源的企业级的快速开发平台。基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 微信小程序，支持 RBAC 动态权限、数据权限、SaaS 多租户、Activiti + Flowable 工作流、三方登录、支付、短信、商城等功能\n    - [`YunaiV/yudao-cloud` ![](https://img.shields.io/github/stars/YunaiV/yudao-cloud.svg?style=social&label=Star)](https://github.com/YunaiV/yudao-cloud)  [![star](https://gitee.com/zhijiantianya/yudao-cloud/badge/star.svg?theme=gray)](https://gitee.com/zhijiantianya/yudao-cloud)  \n      RuoYi-Vue 全新 Cloud 版本，优化重构所有功能。基于 Spring Cloud Alibaba + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序，支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能\n    - [`zlt2000/microservices-platform` ![](https://img.shields.io/github/stars/zlt2000/microservices-platform.svg?style=social&label=Star)](https://github.com/zlt2000/microservices-platform) [![star](https://gitee.com/zlt2000/microservices-platform/badge/star.svg?theme=gray)](https://gitee.com/zlt2000/microservices-platform)  \n      基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba并采用前后端分离的企业级微服务多租户系统架构\n    - [`dromara/lamp-cloud` ![](https://img.shields.io/github/stars/dromara/lamp-cloud.svg?style=social&label=Star)](https://github.com/zuihou/lamp-cloud) [![star](https://gitee.com/dromara/lamp-cloud/badge/star.svg?theme=gray)](https://gitee.com/dromara/lamp-cloud)  \n      基于Jdk11 + SpringCloud + SpringBoot 的微服务快速开发平台，其中的可配置的SaaS功能尤其闪耀， 具备RBAC功能、网关统一鉴权、Xss防跨站攻击、自动代码生成、多种存储系统、分布式事务、分布式定时任务等多个模块，支持多业务系统并行开发， 支持多服务并行开发，可以作为后端服务的开发脚手架\n        - [`zuihou/lamp-util` ![](https://img.shields.io/github/stars/zuihou/lamp-util.svg?style=social&label=Star)](https://github.com/zuihou/lamp-util) [![star](https://gitee.com/zuihou111/lamp-util/badge/star.svg?theme=gray)](https://gitee.com/zuihou111/lamp-util)  \n          打造一套兼顾 SpringBoot 和 SpringCloud 项目的公共工具类\n    - [`matevip/matecloud` ![](https://img.shields.io/github/stars/matevip/matecloud.svg?style=social&label=Star)](https://github.com/matevip/matecloud) [![star](https://gitee.com/matevip/matecloud/badge/star.svg?theme=gray)](https://gitee.com/matevip/matecloud)  \n      一款基于Spring Cloud Alibaba的微服务架构\n    - [`gavenwangcn/vole` ![](https://img.shields.io/github/stars/gavenwangcn/vole.svg?style=social&label=Star)](https://github.com/gavenwangcn/vole)  \n      SpringCloud 微服务业务脚手架\n    - [`liuweijw/fw-cloud-framework` ![](https://img.shields.io/github/stars/liuweijw/fw-cloud-framework.svg?style=social&label=Star)](https://github.com/liuweijw/fw-cloud-framework) [![star](https://gitee.com/liuweijw/fw-cloud-framework/badge/star.svg?theme=gray)](https://gitee.com/liuweijw/fw-cloud-framework)  \n      基于springcloud全家桶开发分布式框架（支持oauth2认证授权、SSO登录、统一下单、微信公众号服务、Shardingdbc分库分表、常见服务监控、链路监控、异步日志、redis缓存等功能），实现基于Vue全家桶等前后端分离项目工程\n    - [`liuht777/Taroco` ![](https://img.shields.io/github/stars/liuht777/Taroco.svg?style=social&label=Star)](https://github.com/liuht777/Taroco)  \n      整合Nacos、Spring Cloud Alibaba，提供了一系列starter组件， 同时提供服务治理、服务监控、OAuth2权限认证，支持服务降级/熔断、服务权重\n    - [`mingyang66/spring-parent` ![](https://img.shields.io/github/stars/mingyang66/spring-parent.svg?style=social&label=Star)](https://github.com/mingyang66/spring-parent)  \n      数据库多数据源、Redis多数据源、日志组件、全链路日志追踪、埋点扩展点、Netty、微服务、开发基础框架支持、异常统一处理、返回值、跨域、API路由、监控等\n    - [`budwk/budwk` ![](https://img.shields.io/github/stars/budwk/budwk.svg?style=social&label=Star)](https://github.com/budwk/budwk) [![star](https://gitee.com/budwk/budwk/badge/star.svg?theme=gray)](https://gitee.com/budwk/budwk)  \n      `BudWk` 原名 [`NutzWk` ![](https://img.shields.io/github/stars/Wizzercn/NutzWk.svg?style=social&label=Star)](https://github.com/Wizzercn/NutzWk) [![star](https://gitee.com/wizzer/NutzWk/badge/star.svg?theme=gray)](https://gitee.com/wizzer/NutzWk)，基于国产框架 nutz 及 nutzboot 开发的开源Web基础项目，集权限体系、系统参数、数据字典、站内消息、定时任务、CMS、微信等最常用功能，不庞杂、不面面俱到，使其具有上手容易、开发便捷、扩展灵活等特性，特别适合各类大中小型定制化项目需求\n    - [`yinjihuan/spring-cloud` ![](https://img.shields.io/github/stars/yinjihuan/spring-cloud.svg?style=social&label=Star)](https://github.com/yinjihuan/spring-cloud)  \n      《Spring Cloud微服务-全栈技术与案例解析》和《Spring Cloud微服务 入门 实战与进阶》配套源码\n    - [`louyanfeng25/ddd-demo` ![](https://img.shields.io/github/stars/louyanfeng25/ddd-demo.svg?style=social&label=Star)](https://github.com/louyanfeng25/ddd-demo)  \n      《深入浅出DDD》讲解的演示项目，为了能够更好的理解Demo中的分层与逻辑处理，我强烈建议你配合小册来深入了解DDD\n    - [`nageoffer/12306` ![](https://img.shields.io/github/stars/nageoffer/12306.svg?style=social&label=Star)](https://github.com/nageoffer/12306)  \n      12306 铁路购票服务是与大家生活和出行相关的关键系统，包括会员、购票、订单、支付和网关等服务。\n\n更多使用`TTL`的开源项目 参见 [![user repos](https://badgen.net/github/dependents-repo/alibaba/transmittable-thread-local?label=user%20repos)](https://github.com/alibaba/transmittable-thread-local/network/dependents)\n\n# 👷 Contributors\n\n- Jerry Lee \\<oldratlee at gmail dot com> [@oldratlee](https://github.com/oldratlee)\n- Yang Fang \\<snoop.fy at gmail dot com> [@driventokill](https://github.com/driventokill)\n- Zava Xu \\<zava.kid at gmail dot com> [@zavakid](https://github.com/zavakid)\n- wuwen \\<wuwen.55 at aliyun dot com> [@wuwen5](https://github.com/wuwen5)\n- rybalkinsd \\<yan.brikl at gmail dot com> [@rybalkinsd](https://github.com/rybalkinsd)\n- David Dai \\<351450944 at qq dot com> [@LNAmp](https://github.com/LNAmp)\n- Your name here :-)\n\n[![GitHub Contributors](https://contrib.rocks/image?repo=alibaba/transmittable-thread-local)](https://github.com/alibaba/transmittable-thread-local/graphs/contributors)\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# 漏洞奖励计划\n\n## 报告\n\n如果您认为自己在本程序中发现了任何安全（技术）漏洞，欢迎您通过 https://security.alibaba.com 向我们提交漏洞报告。\n如果您报告任何安全漏洞，请注意您可能包含以下信息（合格报告）：\n\n* `git`程序`URL`地址，运行的环境\n* 包含必要屏幕截图的详细说明\n* 重现漏洞的步骤以及修复漏洞的建议。\n* 其他有用信息\n\n## 处理\n\nASRC（Alibaba Security Response Center 阿里安全响应中心）将尽快审核并回复您的提交内容，并在我们努力修复您提交的漏洞时随时通知您。如有必要，我们可能会与您联系以获取更多信息。\n\n## 条款和条件\n\n1. 仅接受技术漏洞并对其进行评级\n2. 出于安全原因，上报者同意与ASRC合作完成他/她提交的漏洞，不向任何第三方透露任何漏洞信息\n3. 如果不止一个人报告相同的安全漏洞，奖励将给予完成合格报告的第一个人\n4. 为了保护程序的用户，请在修复之前不要直接提交`git`的`issue`，也不要在社区讨论任何漏洞信息\n5. 所有奖励和声誉积分将提供给仅向ASRC提交其安全漏洞的上报者\n6. 安全漏洞奖励的解释权利归ASRC所有\n\n## 收集范围\n\n我们的主要收集漏洞类别是：\n\n* 服务器端请求伪造（`SSRF`）\n* `SQL`注入\n* 拒绝服务攻击\n* 远程执行代码（`RCE`）\n* XML外部实体攻击（`XXE`）\n* 访问控制问题（不安全的直接对象参考问题等）\n* 敏感目录遍历问题\n* 本地文件读取（`LFD`）\n* 敏感信息泄露（密钥、`Cookie`、`Session`等）\n\n## 奖励\n\n* 可直接导致严重问题的每个漏洞奖励7000元人民币\n* 存在限制及需要一定特殊环境下才能利用的问题将给予700-5600元人民币不等的奖励，比如需要用户主动点击才会触发的问题或需要admin权限\n* 只有在指定环境下才可以运行的利用将有可能被收纳但不给予奖励，或直接被忽略，比如只在`fastjson`+`linux`特定版本才会出现的问题\n\n## 不在收集范围的报告\n\n* 影响过时浏览器或平台用户的漏洞\n* `Self-XSS`\n* 会话固定\n* 内容欺骗\n* 缺少`cookie`标记\n* 混合内容警告\n* `SSL`/`TLS`问题\n* `Clickjacking`\n* 基于`Flash`的漏洞\n* 反射文件下载攻击（`RFD`）\n* 物理或社会工程攻击\n* 未验证自动化工具或扫描仪的结果\n* 登录/注销/未认证/低影响`CSRF`\n* 需要`MITM`或物理访问用户设备的攻击\n* 与网络协议或行业标准相关的问题\n* 不能用于直接攻击的错误信息泄露\n* 缺少与安全相关的`HTTP`标头等\n\n\n# Vulnerability Reward Program\n\n## Reporting\n\nIf you believe you have found any security (technical) vulnerability in the Program, you are welcomed to submit a vulnerability report to us at https://security.alibaba.com\nIn case of reporting any security vulnerability, please be noted that you may including following information (Qualified Reporting):\n\n* The git program URL and running version\n* A detailed description with necessary screenshots\n* Steps to reappearance the vulnerability and your advice to fix it\n* Other useful information\n\n## Processing\n\nASRC (Alibaba Security Response Center) will review and respond as quickly as possible to your submission, and keep you informed as we work to fix the vulnerability you submitted. We may contact you for further information if necessary.\n\n## Terms and Conditions\n\n1. ONLY technical vulnerabilities will be accepted and rated.\n2. With regarding to security reasons, reporters agree to cooperate with ASRC exclusively on the vulnerability he/she submitted and not disclose any information of vulnerability to any third-parties.\n3. In the case that more than one person report the same security vulnerability, the reward will be given to the first person who accomplish a Qualified Reporting.\n4. To protect users of the program, please do not directly submit issue on github or discuss anything with the community\n5. All Rewards and Reputation Credits are given to the reporters who submit his/her security vulnerabilities ONLY to ASRC.\n6. All rights for the security vulnerability rewards are reserved by ASRC.\n\n## Scope of Collecting\n\nThe main categories of vulnerabilities that we are sincerely looking for are:\n\n* Server-Side Request Forgery (`SSRF`)\n* SQL Injection\n* Denial of Service Attack\n* Remote Code Execution (`RCE`)\n* XML External Entity Attacks (`XXE`)\n* Access Control Issues (Insecure Direct Object Reference issues, etc.)\n* Directory Traversal Issues\n* Local File Disclosure (`LFD`)\n* Sensitive Information Leakage (Key, Cookie, Session etc.)\n\n## Reward\n\n* $1,000 for one valid report\n* $100-$800 for Vuls which is limited. For example, Vuls that need user interactions or administrator authority\n* Vuls which only work on the special version will be accepted but no reward, or directly rejected. For example, Vul runs only on a special linux version\n\n## Ineligible Reports\n\n* Vulnerabilities affecting users of outdated browsers or platforms\n* \"Self\" `XSS`\n* Session fixation\n* Content Spoofing\n* Missing cookie flags\n* Mixed content warnings\n* `SSL`/`TLS` best practices\n* Clickjacking/UI redressing\n* Flash-based vulnerabilities\n* Reflected file download attacks (`RFD`)\n* Physical or social engineering attacks\n* Unverified Results of automated tools or scanners\n* Login/logout/unauthenticated/low-impact `CSRF`\n* Attacks requiring MITM or physical access to a user's device\n* Issues related to networking protocols or industry standards\n* Error information disclosure that cannot be used to make a direct attack\n* Missing security-related `HTTP` headers which do not lead directly to a vulnerability\n"
  },
  {
    "path": "docs/developer-guide-en.md",
    "content": "# 🎓 Developer Guide\n\n---------------------------\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n- [📌 Framework/Middleware integration to `TTL` transmittance](#-frameworkmiddleware-integration-to-ttl-transmittance)\n- [📚 Related material](#-related-material)\n    - [`JDK` core classes](#jdk-core-classes)\n    - [`Java` Agent](#java-agent)\n    - [`Javassist`](#javassist)\n    - [`Maven Shade plugin`](#maven-shade-plugin)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n---------------------------\n\n# 📌 Framework/Middleware integration to `TTL` transmittance\n\n[`TransmittableThreadLocal.Transmitter`](../ttl-core/src/main/java/com/alibaba/ttl3/transmitter/Transmitter.java) to capture all `TTL` values of current thread and replay them in another thread.\n\nThere are following methods：\n\n1. `capture`: capture all `TTL` values in current thread\n2. `replay`: replay the captured `TTL` values in the current thread, and return the backup `TTL` values before replay\n3. `restore`: restore `TTL` values before replay\n\nSample code：\n\n```java\n// ===========================================================================\n// Thread A\n// ===========================================================================\n\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<String>();\ncontext.set(\"value-set-in-parent\");\n\n// 1. capture all TTL values in current thread\nfinal Object captured = TransmittableThreadLocal.Transmitter.capture();\n\n// ===========================================================================\n// Thread B\n// ===========================================================================\n\n// 2. replay the captured TTL values in current thread, and return the backup TTL values before replay\nfinal Object backup = TransmittableThreadLocal.Transmitter.replay(captured);\ntry {\n    // Your biz code, you can get the TTL value from here\n    String value = context.get();\n    ...\n} finally {\n    // 3. restore TTL values before replay\n    TransmittableThreadLocal.Transmitter.restore(backup);\n}\n```\n\n\n- For more info about `TransmittableThreadLocal.Transmitter`, see [its Javadoc](../ttl-core/src/main/java/com/alibaba/ttl3/transmitter/Transmitter.java).\n- For more actual implementation code of `TTL` transmittance, see [`TtlRunnable.java`](../ttl-core/src/main/java/com/alibaba/ttl3/TtlRunnable.java) and [`TtlCallable.java`](../ttl-core/src/main/java/com/alibaba/ttl3/TtlCallable.java).\n\n# 📚 Related material\n\n## `JDK` core classes\n\n- [WeakHashMap](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/WeakHashMap.html)\n- [InheritableThreadLocal](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/InheritableThreadLocal.html)\n\n## `Java` Agent\n\n- [Java Agent Specification](https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html)\n\n## `Javassist`\n\n- [Getting Started with Javassist](https://www.javassist.org/tutorial/tutorial.html)\n\n## `Maven Shade plugin`\n\n- [`Maven Shade plugin` doc](https://maven.apache.org/plugins/maven-shade-plugin/)\n"
  },
  {
    "path": "docs/developer-guide.md",
    "content": "# 🎓 Developer Guide\n\n---------------------------\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n- [📌 框架/中间件集成`TTL`传递](#-%E6%A1%86%E6%9E%B6%E4%B8%AD%E9%97%B4%E4%BB%B6%E9%9B%86%E6%88%90ttl%E4%BC%A0%E9%80%92)\n- [📟 关于`Java Agent`](#-%E5%85%B3%E4%BA%8Ejava-agent)\n    - [`Java Agent`方式对应用代码无侵入](#java-agent%E6%96%B9%E5%BC%8F%E5%AF%B9%E5%BA%94%E7%94%A8%E4%BB%A3%E7%A0%81%E6%97%A0%E4%BE%B5%E5%85%A5)\n    - [已有`Java Agent`中嵌入`TTL Agent`](#%E5%B7%B2%E6%9C%89java-agent%E4%B8%AD%E5%B5%8C%E5%85%A5ttl-agent)\n- [👢 `Bootstrap ClassPath`上添加通用库`Jar`的问题及其解决方法](#-bootstrap-classpath%E4%B8%8A%E6%B7%BB%E5%8A%A0%E9%80%9A%E7%94%A8%E5%BA%93jar%E7%9A%84%E9%97%AE%E9%A2%98%E5%8F%8A%E5%85%B6%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95)\n- [🔨 如何编译构建](#-%E5%A6%82%E4%BD%95%E7%BC%96%E8%AF%91%E6%9E%84%E5%BB%BA)\n- [发布操作列表](#%E5%8F%91%E5%B8%83%E6%93%8D%E4%BD%9C%E5%88%97%E8%A1%A8)\n- [📚 相关资料](#-%E7%9B%B8%E5%85%B3%E8%B5%84%E6%96%99)\n    - [`JDK` core classes](#jdk-core-classes)\n    - [`Java Agent`](#java-agent)\n    - [`Javassist`](#javassist)\n    - [`Maven Shade`插件](#maven-shade%E6%8F%92%E4%BB%B6)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n---------------------------\n\n# 📌 框架/中间件集成`TTL`传递\n\n框架/中间件集成`TTL`传递，通过[`TransmittableThreadLocal.Transmitter`](../ttl-core/src/main/java/com/alibaba/ttl3/transmitter/Transmitter.java)\n抓取当前线程的所有`TTL`值并在其他线程进行回放；在回放线程执行完业务操作后，恢复为回放线程原来的`TTL`值。\n\n`TransmittableThreadLocal.Transmitter`提供了所有`TTL`值的抓取、回放和恢复方法（即`CRR`操作）：\n\n1. `capture`方法：抓取线程（线程A）的所有`TTL`值。\n2. `replay`方法：在另一个线程（线程B）中，回放在`capture`方法中抓取的`TTL`值，并返回 回放前`TTL`值的备份\n3. `restore`方法：恢复线程B执行`replay`方法之前的`TTL`值（即备份）\n\n示例代码：\n\n```java\n// ===========================================================================\n// 线程 A\n// ===========================================================================\n\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\ncontext.set(\"value-set-in-parent\");\n\n// (1) 抓取当前线程的所有TTL值\nfinal Object captured = TransmittableThreadLocal.Transmitter.capture();\n\n// ===========================================================================\n// 线程 B（异步线程）\n// ===========================================================================\n\n// (2) 在线程 B中回放在capture方法中抓取的TTL值，并返回 回放前TTL值的备份\nfinal Object backup = TransmittableThreadLocal.Transmitter.replay(captured);\ntry {\n    // 你的业务逻辑，这里你可以获取到外面设置的TTL值\n    String value = context.get();\n\n    System.out.println(\"Hello: \" + value);\n    ...\n    String result = \"World: \" + value;\n} finally {\n    // (3) 恢复线程 B执行replay方法之前的TTL值（即备份）\n    TransmittableThreadLocal.Transmitter.restore(backup);\n}\n```\n\n更多`TTL`传递的代码实现示例，参见 [`TtlRunnable.java`](../ttl-core/src/main/java/com/alibaba/ttl3/TtlRunnable.java)、[`TtlCallable.java`](../ttl-core/src/main/java/com/alibaba/ttl3/TtlCallable.java)。\n\n当然可以使用`TransmittableThreadLocal.Transmitter`的工具方法`runSupplierWithCaptured`和`runCallableWithCaptured`和可爱的`Java 8 Lambda`语法\n来简化`replay`和`restore`操作，示例代码：\n\n```java\n// ===========================================================================\n// 线程 A\n// ===========================================================================\n\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\ncontext.set(\"value-set-in-parent\");\n\n// (1) 抓取当前线程的所有TTL值\nfinal Object captured = TransmittableThreadLocal.Transmitter.capture();\n\n// ===========================================================================\n// 线程 B（异步线程）\n// ===========================================================================\n\nString result = runSupplierWithCaptured(captured, () -> {\n    // 你的业务逻辑，这里你可以获取到外面设置的TTL值\n    String value = context.get();\n    System.out.println(\"Hello: \" + value);\n    ...\n    return \"World: \" + value;\n}); // (2) + (3)\n```\n\n- 更多`TTL`传递的说明，详见[`TransmittableThreadLocal.Transmitter`的`JavaDoc`](../ttl-core/src/main/java/com/alibaba/ttl3/transmitter/Transmitter.java)。\n- 更多`TTL`传递的代码实现，参见[`TtlRunnable.java`](../ttl-core/src/main/java/com/alibaba/ttl3/TtlRunnable.java)、[`TtlCallable.java`](../ttl-core/src/main/java/com/alibaba/ttl3/TtlCallable.java)。\n\n# 📟 关于`Java Agent`\n\n## `Java Agent`方式对应用代码无侵入\n\n[User Guide - 2.3 使用`Java Agent`来修饰`JDK`线程池实现类](../README.md#23-%E4%BD%BF%E7%94%A8java-agent%E6%9D%A5%E4%BF%AE%E9%A5%B0jdk%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AE%9E%E7%8E%B0%E7%B1%BB) 说到了，相对修饰`Runnable`或是线程池的方式，`Java Agent`方式是对应用代码无侵入的。下面做一些展开说明。\n\n<img src=\"scenario-framework-sdk-arch.png\" alt=\"构架图\" width=\"260\" />\n\n按框架图，把前面示例代码操作可以分成下面几部分：\n\n1. 读取信息设置到`TTL`。  \n    这部分在容器中完成，无需应用参与。\n2. 提交`Runnable`到线程池。要有修饰操作`Runnable`（无论是直接修饰`Runnable`还是修饰线程池）。  \n    这部分操作一定是在用户应用中触发。\n3. 读取`TTL`，做业务检查。  \n    在`SDK`中完成，无需应用参与。\n\n只有第2部分的操作和应用代码相关。\n\n如果不通过`Java Agent`修饰线程池，则修饰操作需要应用代码来完成。\n\n使用`Java Agent`方式，应用无需修改代码，即做到 相对应用代码 透明地完成跨线程池的上下文传递。\n\n更多关于应用场景的了解说明参见文档[需求场景](requirement-scenario.md)。\n\n## 已有`Java Agent`中嵌入`TTL Agent`\n\n这样可以减少`Java`启动命令行上的`Agent`的配置。\n\n在自己的`Agent`中加上`TTL Agent`的逻辑，示例代码如下（[`YourXxxAgent.java`](../ttl2-compatible/src/test/java/com/alibaba/demo/ttl/agent/YourXxxAgent.java)）：\n\n```java\nimport com.alibaba.ttl.threadpool.agent.TtlAgent;\nimport com.alibaba.ttl.threadpool.agent.TtlTransformer;\n\nimport java.lang.instrument.ClassFileTransformer;\nimport java.lang.instrument.Instrumentation;\nimport java.util.logging.Logger;\n\npublic final class YourXxxAgent {\n    private static final Logger logger = Logger.getLogger(YourXxxAgent.class.getName());\n\n    public static void premain(String agentArgs, Instrumentation inst) {\n        TtlAgent.premain(agentArgs, inst); // add TTL Transformer\n\n        // add your Transformer\n        ...\n    }\n}\n```\n\n关于`Java Agent`和`ClassFileTransformer`的如何实现可以参考：[`TtlAgent.java`](../ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgent.java)、[`TtlTransformer.java`](../ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/TtlTransformer.java)。\n\n注意，在`bootclasspath`上，还是要加上`TTL Jar`：\n\n```bash\n-Xbootclasspath/a:/path/to/transmittable-thread-local-2.x.y.jar:/path/to/your/agent/jar/files\n```\n\n# 👢 `Bootstrap ClassPath`上添加通用库`Jar`的问题及其解决方法\n\n`TTL Agent`的使用方式，需要将`TTL Jar`加到`Bootstrap ClassPath`上（通过`Java`命令行参数`-Xbootclasspath`）；这样`TTL`的类与`JDK`的标准库的类（如`java.lang.String`）的`ClassLoader`是一样的，都在`Bootstrap ClassPath`上。\n\n`Bootstrap ClassPath`上的类会优先于应用`ClassPath`的`Jar`被加载，并且加载`ClassLoader`不能被改。  \n\\# 当然技术上严格地说，通过`Bootstrap ClassPath`上的类（如标准库的类）是可以改`ClassLoader`的，但这样做一般只会带来各种麻烦的问题。关于`ClassLoader`及其使用注意的介绍说明 可以参见[ClassLoader委托关系的完备配置](https://github.com/oldratlee/land#1-classloader%E5%A7%94%E6%89%98%E5%85%B3%E7%B3%BB%E7%9A%84%E5%AE%8C%E5%A4%87%E9%85%8D%E7%BD%AE)。\n\n`TTL Agent`自己内部实现使用了`Javassist`，即在`Bootstrap ClassPath`上也需要添加`Javassist`。如果应用中也使用了`Javassist`，由于运行时会优先使用`TTL Agent`配置`Bootstrap ClassPath`上的`Javassist`，应用逻辑运行时实际不能选择/指定应用自己的`Javassist`的版本，带来了 应用需要的`Javassist`与`TTL Agent`用的`Javassist`之间的兼容性风险。\n\n可以通过 `repackage`依赖（即 重命名/改写 依赖类的包名）来解决这个问题。`Maven`提供了[`Shade`插件](https://maven.apache.org/plugins/maven-shade-plugin/)，可以完成下面的操作：\n\n- `repackage` `Javassist`的类文件\n- 添加`repackage`过的`Javassist`到`TTL Jar`中\n\n这样操作后，`TTL Agent`不需要依赖外部的`Javassist`依赖，效果上这样的`shade`过的`TTL Jar`是自包含的、在使用上是编译/运行时0依赖的，自然也规避了依赖冲突的问题。\n\n# 🔨 如何编译构建\n\n编译构建的环境要求： **_`JDK 8+`_**；用`Maven`常规的方式执行编译构建即可：  \n\\# 在工程中已经包含了符合版本要求的`Maven`，直接运行 **_工程根目录下的`mvnw`_**；并不需要先手动自己安装好`Maven`。\n\n```bash\n# 运行测试Case\n./mvnw test\n# 编译打包\n./mvnw package\n# 运行测试Case、编译打包、安装TTL库到Maven本地\n./mvnw install\n\n#####################################################\n# 如果使用你自己安装的 maven，版本要求：maven 3.3.9+\nmvn install\n```\n\n# 发布操作列表\n\n详见独立文档 [发布操作列表](release-action-list.md)。\n\n# 📚 相关资料\n\n## `JDK` core classes\n\n- [WeakHashMap](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/WeakHashMap.html)\n- [InheritableThreadLocal](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/InheritableThreadLocal.html)\n\n## `Java Agent`\n\n- 官方文档\n    - [`Java Agent`规范 - `JavaDoc`](https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html#package.description)\n    - [JAR File Specification - JAR Manifest](https://docs.oracle.com/en/java/javase/21/docs/specs/jar/jar.html#jar-manifest)\n    - [Working with Manifest Files - The Java™ Tutorials](https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html)\n- [Java SE 6 新特性: Instrumentation 新功能](https://www.ibm.com/developerworks/cn/java/j-lo-jse61/)\n- [Creation, dynamic loading and instrumentation with javaagents](https://dhruba.name/2010/02/07/creation-dynamic-loading-and-instrumentation-with-javaagents/)\n- [JavaAgent加载机制分析](https://www.iteye.com/blog/nijiaben-1847212/)\n\n## `Javassist`\n\n- [Getting Started with Javassist](https://www.javassist.org/tutorial/tutorial.html)\n\n## `Maven Shade`插件\n\n- [`Maven Shade`插件文档](https://maven.apache.org/plugins/maven-shade-plugin/)\n"
  },
  {
    "path": "docs/logo.md",
    "content": ""
  },
  {
    "path": "docs/performance-test.md",
    "content": "# ☔️ 性能测试\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n\n- [👻 内存泄漏](#-%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F)\n    - [验证结果](#%E9%AA%8C%E8%AF%81%E7%BB%93%E6%9E%9C)\n    - [执行方式](#%E6%89%A7%E8%A1%8C%E6%96%B9%E5%BC%8F)\n- [🐎 TPS & 压力测试](#-tps--%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95)\n    - [验证结果](#%E9%AA%8C%E8%AF%81%E7%BB%93%E6%9E%9C-1)\n        - [TPS略有下降的原因分析](#tps%E7%95%A5%E6%9C%89%E4%B8%8B%E9%99%8D%E7%9A%84%E5%8E%9F%E5%9B%A0%E5%88%86%E6%9E%90)\n        - [FGC次数增多的原因分析](#fgc%E6%AC%A1%E6%95%B0%E5%A2%9E%E5%A4%9A%E7%9A%84%E5%8E%9F%E5%9B%A0%E5%88%86%E6%9E%90)\n    - [执行方式](#%E6%89%A7%E8%A1%8C%E6%96%B9%E5%BC%8F-1)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n## 👻 内存泄漏\n\n对比测试[`TransmittableThreadLocal`](../ttl-core/src/main/java/com/alibaba/ttl3/TransmittableThreadLocal.java)和[`ThreadLocal`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ThreadLocal.html)，测试Case是：\n\n简单一个线程一直循环`new` `TransmittableThreadLocal`、`ThreadLocal`实例，不主动做任何清理操作，即不调用`ThreadLocal`的`remove`方法主动清空。\n\n### 验证结果\n\n都可以持续运行，不会出内存溢出`OutOfMemoryError`。\n\n### 执行方式\n\n可以通过执行工程下的脚本来运行Case验证：\n\n* 脚本[`memoryleak-ThreadLocal.sh`](../scripts/perf-test/memoryleak-ThreadLocal.sh)运行`ThreadLocal`的测试。  \n测试类是[`NoMemoryLeak_ThreadLocal_NoRemove`](../ttl-core/src/test/java/com/alibaba/perf/memoryleak/NoMemoryLeak_ThreadLocal_NoRemove.kt)。\n* 脚本[`memoryleak-TransmittableThreadLocal.sh`](../scripts/perf-test/memoryleak-TransmittableThreadLocal.sh)运行`TransmittableThreadLocal`的测试。\n测试类是[`NoMemoryLeak_TransmittableThreadLocal_NoRemove`](../ttl-core/src/test/java/com/alibaba/perf/memoryleak/NoMemoryLeak_TransmittableThreadLocal_NoRemove.kt)。\n\n## 🐎 TPS & 压力测试\n\n对比测试[`TransmittableThreadLocal`](../ttl-core/src/main/java/com/alibaba/ttl3/TransmittableThreadLocal.java)和[`ThreadLocal`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ThreadLocal.html)，测试Case是：\n\n2个线程并发一直循环`new` `TransmittableThreadLocal`、`ThreadLocal`实例，不主动做任何清理操作，即不调用`ThreadLocal`的`remove`方法主动清空。\n\n### 验证结果\n\n在我的4核开发机上运行了24小时，稳定正常。\n\nTPS结果如下：\n\n`ThreadLocal`的TPS稳定在～41K：\n\n```bash\n......\ntps: 42470\ntps: 40940\ntps: 41041\ntps: 40408\ntps: 40610\n```\n\n`TransmittableThreadLocal`的TPS稳定在～40K：\n\n```bash\n......\ntps: 40461 \ntps: 40101 \ntps: 39989 \ntps: 40684 \ntps: 41174 \n```\n\nGC情况如下（1分钟输出一次）：\n\n`ThreadLocal`的每分钟GC时间是`5.45s`，FGC次数是`0.09`：\n\n```bash\n   S0     S1      E      O      P    YGC      YGCT     FGC     FGCT   GCT\n......\n  0.00  97.66   0.00   8.33  12.70 1470935 2636.215    41    0.229 2636.444\n 97.66   0.00   0.00  17.18  12.70 1473968 2640.597    41    0.229 2640.825\n 98.44   0.00   0.00  25.47  12.70 1477020 2645.265    41    0.229 2645.493\n 96.88   0.00  33.04  34.03  12.70 1480068 2650.149    41    0.229 2650.378\n  0.00  97.66  14.01  41.82  12.70 1483113 2655.262    41    0.229 2655.490\n  0.00  97.66  74.07  50.25  12.70 1486149 2660.596    41    0.229 2660.825\n 96.88   0.00   0.00  58.32  12.70 1489170 2666.135    41    0.229 2666.364\n 98.44   0.00  26.07  67.05  12.70 1492162 2671.841    41    0.229 2672.070\n  0.00  97.66   0.00  76.50  12.70 1495139 2677.809    41    0.229 2678.038\n  0.00  97.66   0.00  85.95  12.70 1498091 2683.994    41    0.229 2684.222\n 96.88   0.00   0.00  96.50  12.70 1501038 2690.454    41    0.229 2690.683\n 97.66   0.00   0.00   7.96  12.70 1504054 2695.583    42    0.233 2695.816\n  0.00  97.66   0.00  17.46  12.70 1507099 2700.009    42    0.233 2700.241\n  0.00  97.66   0.00  26.97  12.70 1510133 2704.652    42    0.233 2704.885\n 97.66   0.00   0.00  36.57  12.70 1513158 2709.592    42    0.233 2709.825\n  0.00  97.66   0.00  45.59  12.70 1516167 2714.738    42    0.233 2714.971\n 98.44   0.00   0.00  54.49  12.70 1519166 2720.109    42    0.233 2720.342\n  0.00  98.44   0.00  63.52  12.70 1522141 2725.688    42    0.233 2725.921\n  0.00  97.66  84.18  72.00  12.70 1525139 2731.579    42    0.233 2731.812\n  0.00  98.44  20.04  80.10  12.70 1528121 2737.680    42    0.233 2737.913\n  0.00  97.66  28.06  87.70  12.70 1531093 2743.991    42    0.233 2744.224\n  0.00  98.44   0.00  95.63  12.70 1534055 2750.508    42    0.233 2750.741\n 97.66   0.00   0.00   4.75  12.70 1537062 2756.196    43    0.239 2756.435\n```\n\n`TransmittableThreadLocal`的每分钟GC时间是`5.29s`，FGC次数是`3.27`：\n\n```bash\n   S0     S1      E      O      P    YGC      YGCT     FGC     FGCT   GCT\n......\n  0.00  98.44   8.01  57.38  12.80 1390879 2571.496  1572    9.820 2581.315\n  0.00  97.66   0.00  78.87  12.80 1393725 2576.784  1575    9.839 2586.623\n 98.44   0.00  14.04   5.83  12.80 1396559 2582.082  1579    9.866 2591.948\n 98.44   0.00   0.00  26.41  12.80 1399394 2587.274  1582    9.885 2597.159\n 98.44  98.44   0.00  50.75  12.80 1402230 2592.506  1585    9.904 2602.410\n 98.44   0.00   0.00  84.37  12.80 1405077 2597.808  1588    9.925 2607.733\n  0.00  98.44   0.00   5.19  12.80 1407926 2603.108  1592    9.952 2613.059\n  0.00  98.44  58.17  29.80  12.80 1410770 2608.314  1595    9.973 2618.287\n 99.22   0.00   0.00  54.14  12.80 1413606 2613.582  1598    9.992 2623.574\n 98.44   0.00   0.00  78.18  12.80 1416444 2618.881  1601   10.012 2628.893\n  0.00  97.66   0.00   7.36  12.80 1419275 2624.167  1605   10.038 2634.205\n  0.00  99.22   0.00  31.04  12.80 1422125 2629.391  1608   10.057 2639.448\n  0.00  98.44   0.00  60.41  12.80 1424974 2634.636  1611   10.077 2644.714\n  0.00  98.44   0.00  84.72  12.80 1427825 2639.929  1614   10.094 2650.024\n  0.00  97.66   0.00  12.32  12.80 1430679 2645.204  1618   10.119 2655.323\n  0.00  98.44  12.05  39.31  12.80 1433539 2650.442  1621   10.141 2660.583\n 86.81   0.00   0.00  67.40  12.80 1436392 2655.743  1624   10.156 2665.899\n 99.22   0.00   0.00  95.25  12.80 1439244 2661.071  1627   10.175 2671.246\n 98.44   0.00   0.00  24.63  12.80 1442090 2666.305  1631   10.201 2676.506\n  0.00  99.22   0.00  52.86  12.80 1444945 2671.546  1634   10.222 2681.769\n 98.44   0.00   0.00  80.38  12.80 1447802 2676.850  1637   10.241 2687.091\n  0.00  87.50   0.00   4.22  12.80 1450658 2682.196  1641   10.268 2692.464\n 99.22   0.00   0.00  33.22  12.80 1453507 2687.386  1644   10.290 2697.676\n```\n\n#### TPS略有下降的原因分析\n\n使用`jvisualvm` Profile方法耗时，`TransmittableThreadLocal`Case的热点方法和`ThreadLocal`Case一样。\n\n略有下降可以认为是Full GC更多引起。\n\n实际使用场景中，`TransmittableThreadLocal`实例个数非常有限，不会有性能问题。\n\n#### FGC次数增多的原因分析\n\n在`TransmittableThreadLocal.holder`中，持有`TransmittableThreadLocal`实例的弱引用，减慢实例的回收，导致Full GC增加。\n\n实际使用场景中，`TransmittableThreadLocal`实例个数非常有限，不会有性能问题。\n\n### 执行方式\n\n可以通过执行工程下的脚本来运行Case验证：\n\n* 脚本[`tps-ThreadLocal.sh`](../scripts/perf-test/tps-ThreadLocal.sh)运行`ThreadLocal`的测试。  \n测试类是[`CreateThreadLocalInstanceTps`](../ttl-core/src/test/java/com/alibaba/perf/tps/CreateThreadLocalInstanceTps.kt)。\n* [`tps-TransmittableThreadLocal.sh`](../scripts/perf-test/tps-TransmittableThreadLocal.sh)运行`TransmittableThreadLocal`的测试。\n测试类是[`CreateTransmittableThreadLocalInstanceTps`](../ttl-core/src/test/java/com/alibaba/perf/tps/CreateTransmittableThreadLocalInstanceTps.kt)。\n"
  },
  {
    "path": "docs/release-action-list.md",
    "content": "发布操作列表\n===============================\n\n1. 准备发布分支\n    1. 如`POM`中有降开发版本，注意 修改 新加`API`的 **_`@since`_** ！！\n    2. 从`master`分支新建发布分支\n    3. 在发布分支上，更新版本号及相关信息\n        - 更新`POM`的版本号成要发布的版本号，去掉`SNAPSHOT`\n        - 更新`README`\n            - 更新badge的引用，由master分支名改成Tag名  \n                - `sed 's/master/v2.x.y/g' -i README*`\n                - `javadoc` badge的JavaDoc链接到固定版本  \n                    https://alibaba.github.io/transmittable-thread-local/apidocs/2.x.y/index.html\n            - 示例`Maven`依赖的版本\n            - 更新`JavaDoc`链接到固定版本\n2. 新建并Push Tag，如`v2.x.y`  \n    - `git tag -m 'release v2.x.y' v2.x.y`\n    - `git push origin v2.x.y`\n3. 等待Tag的CI通过 https://github.com/alibaba/transmittable-thread-local/actions\n4. 执行[`scripts/check-japi-compliance.sh`](../scripts/check-japi-compliance.sh)，检查`API`兼容性\n5. 发布版本到`Maven`中央库  \n    `./mvnw clean && ./mvnw deploy -DperformRelease`\n6. 更新`JavaDoc`\n    1. 生成`JavaDoc`，更新到分支`gh-pages`\n        - `git checkout gh-pages`\n        - `mv target/apidocs apidocs/2.x.y`\n    2. 修改`index.html`<https://alibaba.github.io/transmittable-thread-local/apidocs>的重定向到最新版本的`JavaDoc`\n7. 编写Release Note： <https://github.com/alibaba/transmittable-thread-local/releases>\n8. 升级`Master`分支的开发版本号\n    - 更新 `README`中的示例`Maven`依赖版本\n"
  },
  {
    "path": "docs/requirement-scenario.md",
    "content": "# 🎨 需求场景\n\n在`ThreadLocal`的需求场景即是`TTL`的潜在需求场景，如果你的业务需要『在使用线程池等会池化复用线程的组件情况下传递`ThreadLocal`』则是`TTL`目标场景。\n\n下面是几个典型场景例子。\n\n-------------------------------\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n\n- [🔎 1. 分布式跟踪系统](#-1-%E5%88%86%E5%B8%83%E5%BC%8F%E8%B7%9F%E8%B8%AA%E7%B3%BB%E7%BB%9F)\n- [🌵 2. 日志收集记录系统上下文](#-2-%E6%97%A5%E5%BF%97%E6%94%B6%E9%9B%86%E8%AE%B0%E5%BD%95%E7%B3%BB%E7%BB%9F%E4%B8%8A%E4%B8%8B%E6%96%87)\n    - [`Log4j2 MDC`的`TTL`集成](#log4j2-mdc%E7%9A%84ttl%E9%9B%86%E6%88%90)\n    - [`Logback MDC`的`TTL`集成](#logback-mdc%E7%9A%84ttl%E9%9B%86%E6%88%90)\n- [👜 3. `Request`级`Cache`](#-3-request%E7%BA%A7cache)\n- [🛁 4. 应用容器或上层框架跨应用代码给下层`SDK`传递信息](#-4-%E5%BA%94%E7%94%A8%E5%AE%B9%E5%99%A8%E6%88%96%E4%B8%8A%E5%B1%82%E6%A1%86%E6%9E%B6%E8%B7%A8%E5%BA%94%E7%94%A8%E4%BB%A3%E7%A0%81%E7%BB%99%E4%B8%8B%E5%B1%82sdk%E4%BC%A0%E9%80%92%E4%BF%A1%E6%81%AF)\n    - [上面场景使用`TTL`的整体构架](#%E4%B8%8A%E9%9D%A2%E5%9C%BA%E6%99%AF%E4%BD%BF%E7%94%A8ttl%E7%9A%84%E6%95%B4%E4%BD%93%E6%9E%84%E6%9E%B6)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n-------------------------------\n\n## 🔎 1. 分布式跟踪系统 或 全链路压测（即链路打标）\n\n关于『分布式跟踪系统』可以了解一下`Google`的`Dapper`（介绍的论文：[中文](https://bigbully.github.io/Dapper-translation/)| [英文](https://research.google.com/pubs/pub36356.html)）。分布式跟踪系统作为基础设施，不会限制『使用线程池等会池化复用线程的组件』，并期望对业务逻辑尽可能的透明。\n\n分布式跟踪系统的实现的示意Demo参见[`DistributedTracerUseDemo.kt`](../ttl2-compatible/src/test/java/com/alibaba/demo/distributed_tracer/refcount/DistributedTracerUseDemo.kt)\n\n从技术能力上讲，全链路压测 与 分布式跟踪系统 是一样的，即链路打标。\n\nPS： 多谢 [@wyzssw](https://github.com/https://github.com/wyzssw) 对分布式追踪系统场景说明交流和实现上讨论建议：\n\n- [Issue: 分布式追踪系统场景下，如何使用TTL](https://github.com/alibaba/transmittable-thread-local/issues/53)\n\n## 🌵 2. 日志收集记录系统上下文\n\n由于不限制用户应用使用线程池，系统的上下文需要能跨线程的传递，且不影响应用代码。\n\n### `Log4j2 MDC`的`TTL`集成\n\n`Log4j2`通过[`Thread Context`](https://logging.apache.org/log4j/2.x/manual/thread-context.html)提供了`Mapped Diagnostic Context`（`MDC`，诊断上下文）的功能，通过[`ThreadLocal`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ThreadLocal.html)/[`InheritableThreadLocal`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/InheritableThreadLocal.html)实现上下文传递。\n\n在[`Thread Context文档`](https://logging.apache.org/log4j/2.x/manual/thread-context.html)中提到了在使用线程池等会池化复用线程的组件（如`Executors`）时有问题，需要提供一个机制方案：\n\n> The Stack and the Map are managed per thread and are based on ThreadLocal by default. The Map can be configured to use an InheritableThreadLocal by setting system property isThreadContextMapInheritable to \"true\". When configured this way, the contents of the Map will be passed to child threads. However, as discussed in the [Executors](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/Executors.html#privilegedThreadFactory%28%29) class and in other cases where thread pooling is utilized, the ThreadContext may not always be automatically passed to worker threads. In those cases the pooling mechanism should provide a means for doing so. The getContext() and cloneStack() methods can be used to obtain copies of the Map and Stack respectively.\n\n即是`TTL`要解决的问题，提供`Log4j2 MDC`的`TTL`集成，详见工程[`log4j2-ttl-thread-context-map`](https://github.com/oldratlee/log4j2-ttl-thread-context-map)。对应依赖：\n\n```xml\n<dependency>\n    <groupId>com.alibaba</groupId>\n    <artifactId>log4j2-ttl-thread-context-map</artifactId>\n    <version>1.3.0</version>\n</dependency>\n```\n\n可以在 [maven.org](https://repo1.maven.org/maven2/com/alibaba/log4j2-ttl-thread-context-map/maven-metadata.xml) 查看可用的版本。\n\nPS： 多谢 @bwzhang2011 和 @wuwen5 对日志场景说明交流和实现上讨论建议：\n\n- [Issue: 能否提供与LOG4J(2)中的MDC集成或增强](https://github.com/alibaba/transmittable-thread-local/issues/49)  [@bwzhang2011](https://github.com/bwzhang2011)\n- [Issue: slf4j MDCAdapter with multi-thread-context 支持](https://github.com/alibaba/transmittable-thread-local/issues/51)  [@bwzhang2011](https://github.com/bwzhang2011)\n\n### `Logback MDC`的`TTL`集成\n\n`Logback`的集成参见[@ofpay](https://github.com/ofpay)提供的[`logback-mdc-ttl`](https://github.com/ofpay/logback-mdc-ttl)。对应依赖：\n\n```xml\n<dependency>\n    <groupId>com.ofpay</groupId>\n    <artifactId>logback-mdc-ttl</artifactId>\n    <version>1.0.2</version>\n</dependency>\n```\n\n可以在 [maven.org](https://repo1.maven.org/maven2/com/ofpay/logback-mdc-ttl/maven-metadata.xml) 查看可用的版本。\n\n这个集成已经在 **_线上产品环境_** 使用的。说明详见[欧飞网的使用场景](https://github.com/alibaba/transmittable-thread-local/issues/73#issuecomment-300665308)。\n\n## 👜 3. `Request`级`Cache`\n\n对于计算逻辑复杂业务流程，基础数据读取服务（这样的读取服务往往是个外部远程服务）可能需要多次调用，期望能缓存起来，以避免多次重复执行高成本操作。\n\n同时，在入口发起不同的请求，处理的是不同用户的数据，所以不同发起请求之间不需要共享数据，这样也能避免请求对应的不同用户之间可能的数据污染。\n\n因为涉及多个上下游线程，其实是`Session`级缓存。\n\n通过`Request`级缓存可以\n\n- 避免重复执行高成本操作，提升性能。\n- 避免不同`Request`之间的数据污染。\n\n更多讨论与使用方式参见[**_`@olove`_**](https://github.com/olove) 提的Issue：[讨论：Session级Cache场景下，TransmittableThreadLocal的使用](https://github.com/alibaba/transmittable-thread-local/issues/122)。\n\n## 🛁 4. 应用容器或上层框架跨应用代码给下层`SDK`传递信息\n\n举个具体的业务场景，在`App Engine`（`PAAS`）上会运行由应用提供商提供的应用（`SAAS`模式）。多个`SAAS`用户购买并使用这个应用（即`SAAS`应用）。`SAAS`应用往往是一个实例为多个`SAAS`用户提供服务。  \n\\# 另一种模式是：`SAAS`用户使用完全独立一个`SAAS`应用，包含独立应用实例及其后的数据源（如`DB`、缓存，etc）。\n\n需要避免的`SAAS`应用拿到多个`SAAS`用户的数据。一个解决方法是处理过程关联好一个`SAAS`用户的上下文，在上下文中应用只能处理（读/写）这个`SAAS`用户的数据。请求由`SAAS`用户发起（如从`Web`请求进入`App Engine`），`App Engine`可以知道是从哪个`SAAS`用户，在`Web`请求时在上下文中设置好`SAAS`用户`ID`。应用处理数据（`DB`、`Web`、消息 etc.）是通过`App Engine`提供的服务`SDK`来完成。当应用处理数据时，`SDK`检查数据所属的`SAAS`用户是否和上下文中的`SAAS`用户`ID`一致，如果不一致则拒绝数据的读写。\n\n应用代码会使用线程池，并且这样的使用是正常的业务需求。`SAAS`用户`ID`的从要`App Engine`传递到下层`SDK`，要支持这样的用法。\n\n### 上面场景使用`TTL`的整体构架\n\n<img src=\"scenario-framework-sdk-arch.png\" alt=\"构架图\" width=\"260\" />\n\n构架涉及3个角色：容器、用户应用、`SDK`。\n\n整体流程：\n\n1. 请求进入`PAAS`容器，提取上下文信息并设置好上下文。\n2. 进入用户应用处理业务，业务调用`SDK`（如`DB`、消息、etc）。  \n    用户应用会使用线程池，所以调用`SDK`的线程可能不是请求的线程。\n3. 进入`SDK`处理。  \n    提取上下文的信息，决定是否符合拒绝处理。\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.3.2\n#\n# Optional ENV vars\n# -----------------\n#   JAVA_HOME - location of a JDK home dir, required when download maven via java source\n#   MVNW_REPOURL - repo url base for downloading maven distribution\n#   MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven\n#   MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output\n# ----------------------------------------------------------------------------\n\nset -euf\n[ \"${MVNW_VERBOSE-}\" != debug ] || set -x\n\n# OS specific support.\nnative_path() { printf %s\\\\n \"$1\"; }\ncase \"$(uname)\" in\nCYGWIN* | MINGW*)\n  [ -z \"${JAVA_HOME-}\" ] || JAVA_HOME=\"$(cygpath --unix \"$JAVA_HOME\")\"\n  native_path() { cygpath --path --windows \"$1\"; }\n  ;;\nesac\n\n# set JAVACMD and JAVACCMD\nset_java_home() {\n  # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched\n  if [ -n \"${JAVA_HOME-}\" ]; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ]; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n      JAVACCMD=\"$JAVA_HOME/jre/sh/javac\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n      JAVACCMD=\"$JAVA_HOME/bin/javac\"\n\n      if [ ! -x \"$JAVACMD\" ] || [ ! -x \"$JAVACCMD\" ]; then\n        echo \"The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run.\" >&2\n        echo \"JAVA_HOME is set to \\\"$JAVA_HOME\\\", but \\\"\\$JAVA_HOME/bin/java\\\" or \\\"\\$JAVA_HOME/bin/javac\\\" does not exist.\" >&2\n        return 1\n      fi\n    fi\n  else\n    JAVACMD=\"$(\n      'set' +e\n      'unset' -f command 2>/dev/null\n      'command' -v java\n    )\" || :\n    JAVACCMD=\"$(\n      'set' +e\n      'unset' -f command 2>/dev/null\n      'command' -v javac\n    )\" || :\n\n    if [ ! -x \"${JAVACMD-}\" ] || [ ! -x \"${JAVACCMD-}\" ]; then\n      echo \"The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run.\" >&2\n      return 1\n    fi\n  fi\n}\n\n# hash string like Java String::hashCode\nhash_string() {\n  str=\"${1:-}\" h=0\n  while [ -n \"$str\" ]; do\n    char=\"${str%\"${str#?}\"}\"\n    h=$(((h * 31 + $(LC_CTYPE=C printf %d \"'$char\")) % 4294967296))\n    str=\"${str#?}\"\n  done\n  printf %x\\\\n $h\n}\n\nverbose() { :; }\n[ \"${MVNW_VERBOSE-}\" != true ] || verbose() { printf %s\\\\n \"${1-}\"; }\n\ndie() {\n  printf %s\\\\n \"$1\" >&2\n  exit 1\n}\n\ntrim() {\n  # MWRAPPER-139:\n  #   Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.\n  #   Needed for removing poorly interpreted newline sequences when running in more\n  #   exotic environments such as mingw bash on Windows.\n  printf \"%s\" \"${1}\" | tr -d '[:space:]'\n}\n\n# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties\nwhile IFS=\"=\" read -r key value; do\n  case \"${key-}\" in\n  distributionUrl) distributionUrl=$(trim \"${value-}\") ;;\n  distributionSha256Sum) distributionSha256Sum=$(trim \"${value-}\") ;;\n  esac\ndone <\"${0%/*}/.mvn/wrapper/maven-wrapper.properties\"\n[ -n \"${distributionUrl-}\" ] || die \"cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties\"\n\ncase \"${distributionUrl##*/}\" in\nmaven-mvnd-*bin.*)\n  MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/\n  case \"${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)\" in\n  *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;\n  :Darwin*x86_64) distributionPlatform=darwin-amd64 ;;\n  :Darwin*arm64) distributionPlatform=darwin-aarch64 ;;\n  :Linux*x86_64*) distributionPlatform=linux-amd64 ;;\n  *)\n    echo \"Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version\" >&2\n    distributionPlatform=linux-amd64\n    ;;\n  esac\n  distributionUrl=\"${distributionUrl%-bin.*}-$distributionPlatform.zip\"\n  ;;\nmaven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;\n*) MVN_CMD=\"mvn${0##*/mvnw}\" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;\nesac\n\n# apply MVNW_REPOURL and calculate MAVEN_HOME\n# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>\n[ -z \"${MVNW_REPOURL-}\" ] || distributionUrl=\"$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*\"$_MVNW_REPO_PATTERN\"}\"\ndistributionUrlName=\"${distributionUrl##*/}\"\ndistributionUrlNameMain=\"${distributionUrlName%.*}\"\ndistributionUrlNameMain=\"${distributionUrlNameMain%-bin}\"\nMAVEN_USER_HOME=\"${MAVEN_USER_HOME:-${HOME}/.m2}\"\nMAVEN_HOME=\"${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string \"$distributionUrl\")\"\n\nexec_maven() {\n  unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :\n  exec \"$MAVEN_HOME/bin/$MVN_CMD\" \"$@\" || die \"cannot exec $MAVEN_HOME/bin/$MVN_CMD\"\n}\n\nif [ -d \"$MAVEN_HOME\" ]; then\n  verbose \"found existing MAVEN_HOME at $MAVEN_HOME\"\n  exec_maven \"$@\"\nfi\n\ncase \"${distributionUrl-}\" in\n*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;\n*) die \"distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'\" ;;\nesac\n\n# prepare tmp dir\nif TMP_DOWNLOAD_DIR=\"$(mktemp -d)\" && [ -d \"$TMP_DOWNLOAD_DIR\" ]; then\n  clean() { rm -rf -- \"$TMP_DOWNLOAD_DIR\"; }\n  trap clean HUP INT TERM EXIT\nelse\n  die \"cannot create temp dir\"\nfi\n\nmkdir -p -- \"${MAVEN_HOME%/*}\"\n\n# Download and Install Apache Maven\nverbose \"Couldn't find MAVEN_HOME, downloading and installing it ...\"\nverbose \"Downloading from: $distributionUrl\"\nverbose \"Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName\"\n\n# select .zip or .tar.gz\nif ! command -v unzip >/dev/null; then\n  distributionUrl=\"${distributionUrl%.zip}.tar.gz\"\n  distributionUrlName=\"${distributionUrl##*/}\"\nfi\n\n# verbose opt\n__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''\n[ \"${MVNW_VERBOSE-}\" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v\n\n# normalize http auth\ncase \"${MVNW_PASSWORD:+has-password}\" in\n'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;\nhas-password) [ -n \"${MVNW_USERNAME-}\" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;\nesac\n\nif [ -z \"${MVNW_USERNAME-}\" ] && command -v wget >/dev/null; then\n  verbose \"Found wget ... using wget\"\n  wget ${__MVNW_QUIET_WGET:+\"$__MVNW_QUIET_WGET\"} \"$distributionUrl\" -O \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" || die \"wget: Failed to fetch $distributionUrl\"\nelif [ -z \"${MVNW_USERNAME-}\" ] && command -v curl >/dev/null; then\n  verbose \"Found curl ... using curl\"\n  curl ${__MVNW_QUIET_CURL:+\"$__MVNW_QUIET_CURL\"} -f -L -o \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" \"$distributionUrl\" || die \"curl: Failed to fetch $distributionUrl\"\nelif set_java_home; then\n  verbose \"Falling back to use Java to download\"\n  javaSource=\"$TMP_DOWNLOAD_DIR/Downloader.java\"\n  targetZip=\"$TMP_DOWNLOAD_DIR/$distributionUrlName\"\n  cat >\"$javaSource\" <<-END\n\tpublic class Downloader extends java.net.Authenticator\n\t{\n\t  protected java.net.PasswordAuthentication getPasswordAuthentication()\n\t  {\n\t    return new java.net.PasswordAuthentication( System.getenv( \"MVNW_USERNAME\" ), System.getenv( \"MVNW_PASSWORD\" ).toCharArray() );\n\t  }\n\t  public static void main( String[] args ) throws Exception\n\t  {\n\t    setDefault( new Downloader() );\n\t    java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );\n\t  }\n\t}\n\tEND\n  # For Cygwin/MinGW, switch paths to Windows format before running javac and java\n  verbose \" - Compiling Downloader.java ...\"\n  \"$(native_path \"$JAVACCMD\")\" \"$(native_path \"$javaSource\")\" || die \"Failed to compile Downloader.java\"\n  verbose \" - Running Downloader.java ...\"\n  \"$(native_path \"$JAVACMD\")\" -cp \"$(native_path \"$TMP_DOWNLOAD_DIR\")\" Downloader \"$distributionUrl\" \"$(native_path \"$targetZip\")\"\nfi\n\n# If specified, validate the SHA-256 sum of the Maven distribution zip file\nif [ -n \"${distributionSha256Sum-}\" ]; then\n  distributionSha256Result=false\n  if [ \"$MVN_CMD\" = mvnd.sh ]; then\n    echo \"Checksum validation is not supported for maven-mvnd.\" >&2\n    echo \"Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties.\" >&2\n    exit 1\n  elif command -v sha256sum >/dev/null; then\n    if echo \"$distributionSha256Sum  $TMP_DOWNLOAD_DIR/$distributionUrlName\" | sha256sum -c >/dev/null 2>&1; then\n      distributionSha256Result=true\n    fi\n  elif command -v shasum >/dev/null; then\n    if echo \"$distributionSha256Sum  $TMP_DOWNLOAD_DIR/$distributionUrlName\" | shasum -a 256 -c >/dev/null 2>&1; then\n      distributionSha256Result=true\n    fi\n  else\n    echo \"Checksum validation was requested but neither 'sha256sum' or 'shasum' are available.\" >&2\n    echo \"Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties.\" >&2\n    exit 1\n  fi\n  if [ $distributionSha256Result = false ]; then\n    echo \"Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised.\" >&2\n    echo \"If you updated your Maven version, you need to update the specified distributionSha256Sum property.\" >&2\n    exit 1\n  fi\nfi\n\n# unzip and move\nif command -v unzip >/dev/null; then\n  unzip ${__MVNW_QUIET_UNZIP:+\"$__MVNW_QUIET_UNZIP\"} \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -d \"$TMP_DOWNLOAD_DIR\" || die \"failed to unzip\"\nelse\n  tar xzf${__MVNW_QUIET_TAR:+\"$__MVNW_QUIET_TAR\"} \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -C \"$TMP_DOWNLOAD_DIR\" || die \"failed to untar\"\nfi\nprintf %s\\\\n \"$distributionUrl\" >\"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url\"\nmv -- \"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain\" \"$MAVEN_HOME\" || [ -d \"$MAVEN_HOME\" ] || die \"fail to move MAVEN_HOME\"\n\nclean || :\nexec_maven \"$@\"\n"
  },
  {
    "path": "mvnw.cmd",
    "content": "<# : batch portion\n@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software Foundation (ASF) under one\n@REM or more contributor license agreements.  See the NOTICE file\n@REM distributed with this work for additional information\n@REM regarding copyright ownership.  The ASF licenses this file\n@REM to you under the Apache License, Version 2.0 (the\n@REM \"License\"); you may not use this file except in compliance\n@REM with the License.  You may obtain a copy of the License at\n@REM\n@REM    http://www.apache.org/licenses/LICENSE-2.0\n@REM\n@REM Unless required by applicable law or agreed to in writing,\n@REM software distributed under the License is distributed on an\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n@REM KIND, either express or implied.  See the License for the\n@REM specific language governing permissions and limitations\n@REM under the License.\n@REM ----------------------------------------------------------------------------\n\n@REM ----------------------------------------------------------------------------\n@REM Apache Maven Wrapper startup batch script, version 3.3.2\n@REM\n@REM Optional ENV vars\n@REM   MVNW_REPOURL - repo url base for downloading maven distribution\n@REM   MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven\n@REM   MVNW_VERBOSE - true: enable verbose log; others: silence the output\n@REM ----------------------------------------------------------------------------\n\n@IF \"%__MVNW_ARG0_NAME__%\"==\"\" (SET __MVNW_ARG0_NAME__=%~nx0)\n@SET __MVNW_CMD__=\n@SET __MVNW_ERROR__=\n@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%\n@SET PSModulePath=\n@FOR /F \"usebackq tokens=1* delims==\" %%A IN (`powershell -noprofile \"& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}\"`) DO @(\n  IF \"%%A\"==\"MVN_CMD\" (set __MVNW_CMD__=%%B) ELSE IF \"%%B\"==\"\" (echo %%A) ELSE (echo %%A=%%B)\n)\n@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%\n@SET __MVNW_PSMODULEP_SAVE=\n@SET __MVNW_ARG0_NAME__=\n@SET MVNW_USERNAME=\n@SET MVNW_PASSWORD=\n@IF NOT \"%__MVNW_CMD__%\"==\"\" (%__MVNW_CMD__% %*)\n@echo Cannot start maven from wrapper >&2 && exit /b 1\n@GOTO :EOF\n: end batch / begin powershell #>\n\n$ErrorActionPreference = \"Stop\"\nif ($env:MVNW_VERBOSE -eq \"true\") {\n  $VerbosePreference = \"Continue\"\n}\n\n# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties\n$distributionUrl = (Get-Content -Raw \"$scriptDir/.mvn/wrapper/maven-wrapper.properties\" | ConvertFrom-StringData).distributionUrl\nif (!$distributionUrl) {\n  Write-Error \"cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties\"\n}\n\nswitch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {\n  \"maven-mvnd-*\" {\n    $USE_MVND = $true\n    $distributionUrl = $distributionUrl -replace '-bin\\.[^.]*$',\"-windows-amd64.zip\"\n    $MVN_CMD = \"mvnd.cmd\"\n    break\n  }\n  default {\n    $USE_MVND = $false\n    $MVN_CMD = $script -replace '^mvnw','mvn'\n    break\n  }\n}\n\n# apply MVNW_REPOURL and calculate MAVEN_HOME\n# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>\nif ($env:MVNW_REPOURL) {\n  $MVNW_REPO_PATTERN = if ($USE_MVND) { \"/org/apache/maven/\" } else { \"/maven/mvnd/\" }\n  $distributionUrl = \"$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')\"\n}\n$distributionUrlName = $distributionUrl -replace '^.*/',''\n$distributionUrlNameMain = $distributionUrlName -replace '\\.[^.]*$','' -replace '-bin$',''\n$MAVEN_HOME_PARENT = \"$HOME/.m2/wrapper/dists/$distributionUrlNameMain\"\nif ($env:MAVEN_USER_HOME) {\n  $MAVEN_HOME_PARENT = \"$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain\"\n}\n$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString(\"x2\")}) -join ''\n$MAVEN_HOME = \"$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME\"\n\nif (Test-Path -Path \"$MAVEN_HOME\" -PathType Container) {\n  Write-Verbose \"found existing MAVEN_HOME at $MAVEN_HOME\"\n  Write-Output \"MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD\"\n  exit $?\n}\n\nif (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {\n  Write-Error \"distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl\"\n}\n\n# prepare tmp dir\n$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile\n$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path \"$TMP_DOWNLOAD_DIR_HOLDER.dir\"\n$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null\ntrap {\n  if ($TMP_DOWNLOAD_DIR.Exists) {\n    try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }\n    catch { Write-Warning \"Cannot remove $TMP_DOWNLOAD_DIR\" }\n  }\n}\n\nNew-Item -Itemtype Directory -Path \"$MAVEN_HOME_PARENT\" -Force | Out-Null\n\n# Download and Install Apache Maven\nWrite-Verbose \"Couldn't find MAVEN_HOME, downloading and installing it ...\"\nWrite-Verbose \"Downloading from: $distributionUrl\"\nWrite-Verbose \"Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName\"\n\n$webclient = New-Object System.Net.WebClient\nif ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {\n  $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)\n}\n[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n$webclient.DownloadFile($distributionUrl, \"$TMP_DOWNLOAD_DIR/$distributionUrlName\") | Out-Null\n\n# If specified, validate the SHA-256 sum of the Maven distribution zip file\n$distributionSha256Sum = (Get-Content -Raw \"$scriptDir/.mvn/wrapper/maven-wrapper.properties\" | ConvertFrom-StringData).distributionSha256Sum\nif ($distributionSha256Sum) {\n  if ($USE_MVND) {\n    Write-Error \"Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties.\"\n  }\n  Import-Module $PSHOME\\Modules\\Microsoft.PowerShell.Utility -Function Get-FileHash\n  if ((Get-FileHash \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {\n    Write-Error \"Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property.\"\n  }\n}\n\n# unzip and move\nExpand-Archive \"$TMP_DOWNLOAD_DIR/$distributionUrlName\" -DestinationPath \"$TMP_DOWNLOAD_DIR\" | Out-Null\nRename-Item -Path \"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain\" -NewName $MAVEN_HOME_NAME | Out-Null\ntry {\n  Move-Item -Path \"$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME\" -Destination $MAVEN_HOME_PARENT | Out-Null\n} catch {\n  if (! (Test-Path -Path \"$MAVEN_HOME\" -PathType Container)) {\n    Write-Error \"fail to move MAVEN_HOME\"\n  }\n} finally {\n  try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }\n  catch { Write-Warning \"Cannot remove $TMP_DOWNLOAD_DIR\" }\n}\n\nWrite-Output \"MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD\"\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.alibaba.ttl3</groupId>\n\t<artifactId>ttl3-parent</artifactId>\n\t<version>3.x-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<name>${project.artifactId}</name>\n\t<description>\n\t\t📌 The missing Java™ std lib(simple &amp; 0-dependency) for framework/middleware, provide an enhanced\n\t\tInheritableThreadLocal that transmits values between threads even using thread pooling components.\n\t</description>\n\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t<inceptionYear>2013</inceptionYear>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache 2</name>\n\t\t\t<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t\t<comments>A business-friendly OSS license</comments>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<connection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</connection>\n\t\t<developerConnection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</developerConnection>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t</scm>\n\t<issueManagement>\n\t\t<system>GitHub Issues</system>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/issues</url>\n\t</issueManagement>\n\t<ciManagement>\n\t\t<system>GitHub Actions</system>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/actions</url>\n\t</ciManagement>\n\t<organization>\n\t\t<name>Alibaba</name>\n\t\t<url>https://www.alibaba.com</url>\n\t</organization>\n\t<developers>\n\t\t<developer>\n\t\t\t<name>Jerry Lee</name>\n\t\t\t<id>oldratlee</id>\n\t\t\t<email>oldratlee(AT)gmail(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/oldratlee</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t</developers>\n\n\t<modules>\n\t\t<module>ttl-core</module>\n\t\t<module>ttl-agent</module>\n\n\t\t<module>ttl-kotlin</module>\n\t\t<module>ttl2-compatible</module>\n\n\t\t<module>ttl-bom</module>\n\n\t\t<module>ttl-integrations/vertx4-ttl-integration</module>\n\t\t<module>ttl-integrations/vertx3-ttl-integration</module>\n\n\t\t<module>ttl-integrations/sample-ttl-agent-extension-transformlet</module>\n\t</modules>\n\n\t<properties>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>${maven.compiler.source}</maven.compiler.target>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<!-- overridden by submodule that need skip deploy -->\n\t\t<maven.deploy.skip>false</maven.deploy.skip>\n\t\t<javadoc.ttl.base.link>\n\t\t\thttps://alibaba.github.io/transmittable-thread-local/apidocs/${project.version}\n\t\t</javadoc.ttl.base.link>\n\n\t\t<spotbugs.annotations.version>4.8.6</spotbugs.annotations.version>\n\t\t<jsr305.version>3.0.2</jsr305.version>\n\t\t<jetbrains.annotations.version>24.1.0</jetbrains.annotations.version>\n\n\t\t<kotlin.version>1.9.25</kotlin.version>\n\t\t<kotlin.compiler.jvmTarget>${maven.compiler.source}</kotlin.compiler.jvmTarget>\n\t\t<kotlin.coroutine.version>1.9.0</kotlin.coroutine.version>\n\t\t<!-- https://kotlin.github.io/dokka/1.7.10/user_guide/maven/usage/ -->\n\t\t<dokka.version>1.9.20</dokka.version>\n\t\t<dokka.link.jdk.version>8</dokka.link.jdk.version>\n\n\t\t<slf4j.version>2.0.7</slf4j.version>\n\n\t\t<!-- testing dependencies versions -->\n\t\t<junit5.version>5.11.4</junit5.version>\n\t\t<kotest.version>5.9.1</kotest.version>\n\n\t\t<!--\n\t\t\tslf4j simple logger configuration for test\n\n\t\t\tthe system properties are supported to configure the behavior of slf4j simple logger\n\t\t\thttps://www.slf4j.org/api/org/slf4j/simple/SimpleLogger.html\n\t\t-->\n\t\t<ttl.test.logger.level>warn</ttl.test.logger.level> <!-- overridden by maven -D options -->\n\t\t<argLine.slf4j.simple.logger.default.d.options>\n\t\t\t-Dorg.slf4j.simpleLogger.logFile=System.err\n\t\t\t-Dorg.slf4j.simpleLogger.defaultLogLevel=${ttl.test.logger.level}\n\t\t</argLine.slf4j.simple.logger.default.d.options>\n\t\t<argLine.slf4j.simple.logger.extra.d.options/> <!-- overridden by maven -D options -->\n\t\t<argLine.slf4j.simple.logger.d.options>\n\t\t\t${argLine.slf4j.simple.logger.default.d.options} ${argLine.slf4j.simple.logger.extra.d.options}\n\t\t</argLine.slf4j.simple.logger.d.options>\n\n\t\t<argLine>${argLine.slf4j.simple.logger.d.options}</argLine> <!-- overridden by profile -->\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- QA libs -->\n\t\t<dependency>\n\t\t\t<groupId>com.github.spotbugs</groupId>\n\t\t\t<artifactId>spotbugs-annotations</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.code.findbugs</groupId>\n\t\t\t<artifactId>jsr305</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.jetbrains</groupId>\n\t\t\t<artifactId>annotations</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<!-- logging libs -->\n\t\t<dependency>\n\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t<artifactId>slf4j-simple</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.github.microutils</groupId>\n\t\t\t<artifactId>kotlin-logging-jvm</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- testing libs -->\n\t\t<dependency>\n\t\t\t<groupId>io.kotest</groupId>\n\t\t\t<artifactId>kotest-runner-junit4-jvm</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.kotest</groupId>\n\t\t\t<artifactId>kotest-runner-junit5-jvm</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.kotest</groupId>\n\t\t\t<artifactId>kotest-assertions-core-jvm</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.kotest</groupId>\n\t\t\t<artifactId>kotest-property-jvm</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.mockk</groupId>\n\t\t\t<artifactId>mockk-jvm</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<!--\n\t\t\tExecuting JUnit 4 and JUnit 5 tests in a same build\n\t\t\t\thttps://stackoverflow.com/a/47158584/922688\n\t\t-->\n\t\t<dependency>\n\t\t\t<!-- JUnit Jupiter Engine to depend on the JUnit5 engine and JUnit 5 API -->\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<!-- JUnit Jupiter Engine to depend on the JUnit4 engine and JUnit 4 API  -->\n\t\t\t<groupId>org.junit.vintage</groupId>\n\t\t\t<artifactId>junit-vintage-engine</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<!-- bom -->\n\t\t\t<dependency>\n\t\t\t\t<!-- https://github.com/raphw/byte-buddy/issues/1264 -->\n\t\t\t\t<groupId>net.bytebuddy</groupId>\n\t\t\t\t<artifactId>byte-buddy-parent</artifactId>\n\t\t\t\t<version>1.15.11</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.jetbrains.kotlin</groupId>\n\t\t\t\t<artifactId>kotlin-bom</artifactId>\n\t\t\t\t<version>${kotlin.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.jetbrains.kotlinx</groupId>\n\t\t\t\t<artifactId>kotlinx-coroutines-bom</artifactId>\n\t\t\t\t<version>${kotlin.coroutine.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.junit</groupId>\n\t\t\t\t<artifactId>junit-bom</artifactId>\n\t\t\t\t<version>${junit5.version}</version>\n\t\t\t\t<type>pom</type>\n\t\t\t\t<scope>import</scope>\n\t\t\t</dependency>\n\n\t\t\t<!--\n\t\t\t\tQA libs\n\t\t\t\tmake qa libs optional, 0-dependency and smaller deployment\n\t\t\t-->\n\t\t\t<dependency>\n\t\t\t\t<!--\n\t\t\t\t\tJSR305 is already Dormant status, so SpotBugs does not release jsr305 jar file.\n\t\t\t\t\tPlease continue using findbugs’ one.\n\t\t\t\t\tdepend on spotbugs-annotations instead.\n\t\t\t\t\thttps://spotbugs.readthedocs.io/en/stable/migration.html\n\t\t\t\t-->\n\t\t\t\t<groupId>com.github.spotbugs</groupId>\n\t\t\t\t<artifactId>spotbugs-annotations</artifactId>\n\t\t\t\t<version>${spotbugs.annotations.version}</version>\n\t\t\t\t<optional>true</optional>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.google.code.findbugs</groupId>\n\t\t\t\t<artifactId>jsr305</artifactId>\n\t\t\t\t<version>${jsr305.version}</version>\n\t\t\t\t<optional>true</optional>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<!-- https://www.jetbrains.com/help/idea/annotating-source-code.html -->\n\t\t\t\t<groupId>org.jetbrains</groupId>\n\t\t\t\t<artifactId>annotations</artifactId>\n\t\t\t\t<version>${jetbrains.annotations.version}</version>\n\t\t\t\t<optional>true</optional>\n\t\t\t</dependency>\n\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.javassist</groupId>\n\t\t\t\t<artifactId>javassist</artifactId>\n\t\t\t\t<version>3.30.2-GA</version>\n\t\t\t\t<optional>true</optional>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t\t<version>3.12.0</version>\n\t\t\t</dependency>\n\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.reactivex.rxjava2</groupId>\n\t\t\t\t<artifactId>rxjava</artifactId>\n\t\t\t\t<version>2.2.21</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.reactivex.rxjava2</groupId>\n\t\t\t\t<artifactId>rxkotlin</artifactId>\n\t\t\t\t<version>2.4.0</version>\n\t\t\t</dependency>\n\n\t\t\t<!-- logging libs -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t<artifactId>slf4j-api</artifactId>\n\t\t\t\t<version>${slf4j.version}</version>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>org.slf4j</groupId>\n\t\t\t\t<artifactId>slf4j-simple</artifactId>\n\t\t\t\t<version>${slf4j.version}</version>\n\t\t\t\t<scope>test</scope>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.github.microutils</groupId>\n\t\t\t\t<artifactId>kotlin-logging-jvm</artifactId>\n\t\t\t\t<version>3.0.0</version>\n\t\t\t</dependency>\n\n\t\t\t<!--\n\t\t\t\ttesting libs\n\t\t\t-->\n\t\t\t<!-- https://github.com/kotlintest/kotlintest -->\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.kotest</groupId>\n\t\t\t\t<artifactId>kotest-runner-junit4-jvm</artifactId>\n\t\t\t\t<version>${kotest.version}</version>\n\t\t\t\t<scope>test</scope>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.kotest</groupId>\n\t\t\t\t<artifactId>kotest-runner-junit5-jvm</artifactId>\n\t\t\t\t<version>${kotest.version}</version>\n\t\t\t\t<scope>test</scope>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.kotest</groupId>\n\t\t\t\t<artifactId>kotest-assertions-core-jvm</artifactId>\n\t\t\t\t<version>${kotest.version}</version>\n\t\t\t\t<scope>test</scope>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.kotest</groupId>\n\t\t\t\t<artifactId>kotest-property-jvm</artifactId>\n\t\t\t\t<version>${kotest.version}</version>\n\t\t\t\t<scope>test</scope>\n\t\t\t</dependency>\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.mockk</groupId>\n\t\t\t\t<artifactId>mockk-jvm</artifactId>\n\t\t\t\t<version>1.14.5</version>\n\t\t\t\t<scope>test</scope>\n\t\t\t</dependency>\n\t\t</dependencies>\n\t</dependencyManagement>\n\n\t<distributionManagement>\n\t\t<snapshotRepository>\n\t\t\t<id>ossrh</id>\n\t\t\t<url>https://oss.sonatype.org/content/repositories/snapshots</url>\n\t\t</snapshotRepository>\n\t</distributionManagement>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<!--\n\t\t\t\t\tCompiling Kotlin and Java sources - Using Maven - Kotlin Programming Language\n\t\t\t\t\thttps://kotlinlang.org/docs/reference/using-maven.html#compiling-kotlin-and-java-sources\n\n\t\t\t\t\tMaking sure that the kotlin plugin is above the maven-compiler-plugin in your pom.xml file!\n\t\t\t\t-->\n\t\t\t\t<groupId>org.jetbrains.kotlin</groupId>\n\t\t\t\t<artifactId>kotlin-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>compile</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>compile</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<sourceDirs>\n\t\t\t\t\t\t\t\t<sourceDir>${project.basedir}/src/main/java</sourceDir>\n\t\t\t\t\t\t\t</sourceDirs>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>test-compile</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>test-compile</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<sourceDirs>\n\t\t\t\t\t\t\t\t<sourceDir>${project.basedir}/src/test/java</sourceDir>\n\t\t\t\t\t\t\t</sourceDirs>\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</plugin>\n\t\t\t<plugin>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<!-- Replacing default-compile as it is treated specially by maven -->\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>default-compile</id>\n\t\t\t\t\t\t<phase>none</phase>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<!-- Replacing default-testCompile as it is treated specially by maven -->\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>default-testCompile</id>\n\t\t\t\t\t\t<phase>none</phase>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>java-compile</id>\n\t\t\t\t\t\t<phase>compile</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>compile</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>java-test-compile</id>\n\t\t\t\t\t\t<phase>test-compile</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>testCompile</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<artifactId>maven-enforcer-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>enforces</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>enforce</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<rules>\n\t\t\t\t\t\t\t\t<!-- official docs: https://maven.apache.org/enforcer/enforcer-rules/requireMavenVersion.html -->\n\t\t\t\t\t\t\t\t<requireMavenVersion>\n\t\t\t\t\t\t\t\t\t<version>3.3.9</version>\n\t\t\t\t\t\t\t\t</requireMavenVersion>\n\t\t\t\t\t\t\t</rules>\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</plugin>\n\t\t</plugins>\n\t\t<pluginManagement>\n\t\t\t<plugins>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-clean-plugin</artifactId>\n\t\t\t\t\t<version>3.4.0</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-resources-plugin</artifactId>\n\t\t\t\t\t<version>3.3.1</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>org.jetbrains.kotlin</groupId>\n\t\t\t\t\t<artifactId>kotlin-maven-plugin</artifactId>\n\t\t\t\t\t<version>${kotlin.version}</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t\t<version>3.14.0</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t\t<version>3.5.2</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t\t<version>3.4.2</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-shade-plugin</artifactId>\n\t\t\t\t\t<version>3.6.0</version>\n\t\t\t\t\t<configuration>\n\t\t\t\t\t\t<shadeSourcesContent>true</shadeSourcesContent>\n\t\t\t\t\t\t<dependencyReducedPomLocation>\n\t\t\t\t\t\t\t${project.build.directory}/dependency-reduced-pom.xml\n\t\t\t\t\t\t</dependencyReducedPomLocation>\n\t\t\t\t\t</configuration>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t\t<version>3.3.1</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t\t<version>3.8.0</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>org.jetbrains.dokka</groupId>\n\t\t\t\t\t<artifactId>dokka-maven-plugin</artifactId>\n\t\t\t\t\t<version>${dokka.version}</version>\n\t\t\t\t\t<executions>\n\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t<phase>prepare-package</phase>\n\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t<goal>javadocJar</goal>\n\t\t\t\t\t\t\t\t<goal>dokka</goal>\n\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t</execution>\n\t\t\t\t\t</executions>\n\t\t\t\t\t<configuration>\n\t\t\t\t\t\t<jdkVersion>${dokka.link.jdk.version}</jdkVersion>\n\t\t\t\t\t</configuration>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t\t<version>3.2.7</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-site-plugin</artifactId>\n\t\t\t\t\t<version>3.21.0</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-install-plugin</artifactId>\n\t\t\t\t\t<version>3.1.3</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t\t<version>3.1.3</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-enforcer-plugin</artifactId>\n\t\t\t\t\t<version>3.5.0</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>io.github.git-commit-id</groupId>\n\t\t\t\t\t<artifactId>git-commit-id-maven-plugin</artifactId>\n\t\t\t\t\t<version>9.0.1</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>com.github.spotbugs</groupId>\n\t\t\t\t\t<artifactId>spotbugs-maven-plugin</artifactId>\n\t\t\t\t\t<version>4.8.3.1</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>org.jacoco</groupId>\n\t\t\t\t\t<artifactId>jacoco-maven-plugin</artifactId>\n\t\t\t\t\t<version>0.8.12</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<!--\n\t\t\t\t\t\thttps://www.mojohaus.org/exec-maven-plugin/\n\t\t\t\t\t\thttps://www.mojohaus.org/exec-maven-plugin/exec-mojo.html\n\t\t\t\t\t-->\n\t\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t\t<artifactId>exec-maven-plugin</artifactId>\n\t\t\t\t\t<version>3.4.1</version>\n\t\t\t\t\t<configuration>\n\t\t\t\t\t\t<executable>${java.home}/bin/java</executable>\n\t\t\t\t\t\t<classpathScope>test</classpathScope>\n\t\t\t\t\t\t<arguments>\n\t\t\t\t\t\t\t<argument>-Xmx1g</argument>\n\t\t\t\t\t\t\t<argument>-Xms256m</argument>\n\t\t\t\t\t\t\t<argument>-ea</argument>\n\t\t\t\t\t\t\t<argument>-server</argument>\n\t\t\t\t\t\t\t<argument>-Duser.language=en</argument>\n\t\t\t\t\t\t\t<argument>-Duser.country=US</argument>\n\n\t\t\t\t\t\t\t<argument>-classpath</argument>\n\t\t\t\t\t\t\t<classpath/>\n\n\t\t\t\t\t\t\t<argument>${exec.mainClass}</argument>\n\t\t\t\t\t\t</arguments>\n\t\t\t\t\t</configuration>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>org.sonatype.plugins</groupId>\n\t\t\t\t\t<artifactId>nexus-staging-maven-plugin</artifactId>\n\t\t\t\t\t<version>1.7.0</version>\n\t\t\t\t</plugin>\n\t\t\t</plugins>\n\t\t</pluginManagement>\n\t</build>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>gen-src</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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<artifactId>maven-source-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\t<profile>\n\t\t\t<id>gen-api-doc</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\n\t\t\t</activation>\n\t\t\t<properties>\n\t\t\t\t<javadoc.default.exclude.packages>\n\t\t\t\t\t*.internal:*.internal.*:*.internal.*.*:*.internal.*.*.*:*.internal.*.*.*.*\n\t\t\t\t</javadoc.default.exclude.packages>\n\t\t\t\t<!--\n\t\t\t\t\tApache Maven Javadoc Plugin – Configuring links and offlineLinks Parameters\n\t\t\t\t\thttps://maven.apache.org/plugins/maven-javadoc-plugin/examples/links-configuration.html\n\n\t\t\t\t\tmore infos about link setting:\n\t\t\t\t\tLinks to JSR 305 in Javadoc are broken https://github.com/google/guava/issues/2479\n\t\t\t\t\tFix links to javadoc.io for Maven Javadoc Plugin #2628 https://github.com/google/guava/pull/2628\n\t\t\t\t\tCan't link to JDK10 in Javadoc comments https://stackoverflow.com/questions/49457896\n\n\t\t\t\t\tAbout package-list vs.element-list\n\t\t\t\t\t- Can't link to JDK10 in Javadoc comments\n\t\t\t\t\t\thttps://stackoverflow.com/a/49498219/922688\n\t\t\t\t\t- Missing javadoc/package-list for release 5.1\n\t\t\t\t\t\thttps://github.com/gradle/gradle/issues/8183\n\t\t\t\t\t\thttps://github.com/gradle/gradle/commit/5e88351dd456a5252d21f3a7ad25bff1b62a2fd2\n\n\n\t\t\t\t\tUsing the linkoffline Option\n\t\t\t\t\thttps://docs.oracle.com/en/java/javase/21/javadoc/javadoc-command.html#GUID-51213F2C-6E01-4A03-A82A-17428A258A0F\n\t\t\t\t-->\n\t\t\t\t<javadoc.package.list.dir>${maven.multiModuleProjectDirectory}/src/package-list</javadoc.package.list.dir>\n\t\t\t\t<!-- dummy/repeated value, overridden by submodule -->\n\t\t\t\t<javadoc.extra.offlineLinks>-quiet</javadoc.extra.offlineLinks>\n\t\t\t</properties>\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<!--\n\t\t\t\t\t\t\thttps://maven.apache.org/plugins/maven-javadoc-plugin/javadoc-mojo.html\n\t\t\t\t\t\t\thttps://docs.oracle.com/en/java/javase/21/javadoc/javadoc-command.html\n\t\t\t\t\t\t-->\n\t\t\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<source>8</source>\n\t\t\t\t\t\t\t<show>protected</show>\n\t\t\t\t\t\t\t<charset>UTF-8</charset>\n\t\t\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t\t\t\t<docencoding>UTF-8</docencoding>\n\t\t\t\t\t\t\t<quiet>true</quiet>\n\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\tHow to disable Javadoc warnings in Maven Javadoc Plugin? - Stack Overflow\n\t\t\t\t\t\t\t\thttps://stackoverflow.com/questions/39616344\n\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t<doclint>all,-missing</doclint>\n\t\t\t\t\t\t\t<overview>${project.basedir}/src/main/javadoc/overview.html</overview>\n\t\t\t\t\t\t\t<!-- https://maven.apache.org/plugins/maven-javadoc-plugin/examples/exclude-package-names.html -->\n\t\t\t\t\t\t\t<excludePackageNames>${javadoc.default.exclude.packages}</excludePackageNames>\n\t\t\t\t\t\t\t<!-- https://maven.apache.org/plugins/maven-javadoc-plugin/javadoc-mojo.html#detectOfflineLinks -->\n\t\t\t\t\t\t\t<detectOfflineLinks>false</detectOfflineLinks>\n\t\t\t\t\t\t\t<additionalOptions>\n\t\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\t\tMaven javadoc Search redirects to \"/undefined/..\" url - Stack Overflow\n\t\t\t\t\t\t\t\t\thttps://stackoverflow.com/questions/52326318\n\t\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t\t<additionalOption>-html5</additionalOption>\n\n\t\t\t\t\t\t\t\t<additionalOption>-linkoffline</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>\n\t\t\t\t\t\t\t\t\thttps://www.javadoc.io/doc/com.github.spotbugs/spotbugs-annotations/${spotbugs.annotations.version}/\n\t\t\t\t\t\t\t\t</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>${javadoc.package.list.dir}/spotbugs-annotations/</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>-linkoffline</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>\n\t\t\t\t\t\t\t\t\thttps://www.javadoc.io/doc/org.jetbrains/annotations/${jetbrains.annotations.version}/\n\t\t\t\t\t\t\t\t</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>${javadoc.package.list.dir}/jetbrains-annotations/</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>-linkoffline</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>\n\t\t\t\t\t\t\t\t\thttps://www.javadoc.io/doc/com.google.code.findbugs/jsr305/${jsr305.version}/\n\t\t\t\t\t\t\t\t</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>${javadoc.package.list.dir}/jsr305/</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>-linkoffline</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>https://docs.oracle.com/en/java/javase/21/docs/api/java.base/</additionalOption>\n\t\t\t\t\t\t\t\t<additionalOption>${javadoc.package.list.dir}/java/</additionalOption>\n\n\t\t\t\t\t\t\t\t<additionalOption>${javadoc.extra.offlineLinks}</additionalOption>\n\t\t\t\t\t\t\t</additionalOptions>\n\t\t\t\t\t\t\t<additionalJOptions>\n\t\t\t\t\t\t\t\t<additionalJOption>-J-Duser.language=en</additionalJOption>\n\t\t\t\t\t\t\t\t<additionalJOption>-J-Duser.country=US</additionalJOption>\n\t\t\t\t\t\t\t</additionalJOptions>\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>gen-sign</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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<artifactId>maven-gpg-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>sign-artifacts</id>\n\t\t\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t\t\t</goals>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>lint</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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<!--\n\t\t\t\t\t\t\thttps://spotbugs.github.io/\n\t\t\t\t\t\t\thttps://spotbugs.readthedocs.io/en/latest/introduction.html\n\t\t\t\t\t\t\thttps://spotbugs.readthedocs.io/en/latest/maven.html\n\n\t\t\t\t\t\t\thttps://spotbugs.github.io/spotbugs-maven-plugin/check-mojo.html\n\t\t\t\t\t\t\t\tBinds by default to the lifecycle phase: verify.\n\n\t\t\t\t\t\t\tSpotbugs support @SuppressWarnings\n\t\t\t\t\t\t\thttps://github.com/spotbugs/spotbugs/issues/737#issuecomment-416118033\n\t\t\t\t\t\t-->\n\t\t\t\t\t\t<groupId>com.github.spotbugs</groupId>\n\t\t\t\t\t\t<artifactId>spotbugs-maven-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<phase>verify</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>check</goal>\n\t\t\t\t\t\t\t\t</goals>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>gen-git-properties</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\n\t\t\t</activation>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<!--\n\t\t\t\t\t\tMaven plugin which includes build-time git repository information into an POJO / *.properties).\n\t\t\t\t\t\tMake your apps tell you which version exactly they were built from! Priceless in large distributed deployments.\n\t\t\t\t\t\t\thttps://github.com/git-commit-id/git-commit-id-maven-plugin\n\t\t\t\t\t-->\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>io.github.git-commit-id</groupId>\n\t\t\t\t\t\t<artifactId>git-commit-id-maven-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>get-the-git-infos</id>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>revision</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>validate-the-git-infos</id>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>validateRevision</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<validationProperties>\n\t\t\t\t\t\t\t\t<!-- verify that the current repository is not dirty -->\n\t\t\t\t\t\t\t\t<validationProperty>\n\t\t\t\t\t\t\t\t\t<name>validating git dirty</name>\n\t\t\t\t\t\t\t\t\t<value>${git.dirty}</value>\n\t\t\t\t\t\t\t\t\t<shouldMatchTo>false</shouldMatchTo>\n\t\t\t\t\t\t\t\t</validationProperty>\n\t\t\t\t\t\t\t</validationProperties>\n\t\t\t\t\t\t\t<generateGitPropertiesFile>true</generateGitPropertiesFile>\n\t\t\t\t\t\t\t<generateGitPropertiesFilename>\n\t\t\t\t\t\t\t\t${project.build.outputDirectory}/META-INF/scm/${project.groupId}/${project.artifactId}/git.properties\n\t\t\t\t\t\t\t</generateGitPropertiesFilename>\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>gen-code-cov</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<!-- https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables -->\n\t\t\t\t\t<name>env.CI</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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<!-- for codecov.io -->\n\t\t\t\t\t\t<!-- config example: https://github.com/codecov/example-java -->\n\t\t\t\t\t\t<!-- plugin docs: https://eclemma.org/jacoco/trunk/doc/ -->\n\t\t\t\t\t\t<groupId>org.jacoco</groupId>\n\t\t\t\t\t\t<artifactId>jacoco-maven-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<goals>\n\t\t\t\t\t\t\t\t\t<goal>prepare-agent</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>report</id>\n\t\t\t\t\t\t\t\t<phase>test</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>report</goal>\n\t\t\t\t\t\t\t\t</goals>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>enforce-when-release</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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<artifactId>maven-enforcer-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>enforces</id>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>enforce</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<rules>\n\t\t\t\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\t\t\t\tadd maven-enforcer-plugin to make sure the right jdk is used\n\t\t\t\t\t\t\t\t\t\t\thttps://stackoverflow.com/a/18420462/922688\n\t\t\t\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t\t\t\t<requireJavaVersion>\n\t\t\t\t\t\t\t\t\t\t\t<version>17</version>\n\t\t\t\t\t\t\t\t\t\t</requireJavaVersion>\n\t\t\t\t\t\t\t\t\t\t<!-- https://maven.apache.org/enforcer/enforcer-rules/requireProperty.html -->\n\t\t\t\t\t\t\t\t\t\t<requireProperty>\n\t\t\t\t\t\t\t\t\t\t\t<property>project.version</property>\n\t\t\t\t\t\t\t\t\t\t\t<regex>^\\d\\.\\d+\\.\\d+(-(Alpha|Beta|RC)\\d+)?$|^\\d(\\.\\d+)?\\.(\\d+|x)-SNAPSHOT$</regex>\n\t\t\t\t\t\t\t\t\t\t\t<regexMessage>\"Project version(${project.version}) format is invalid!\"</regexMessage>\n\t\t\t\t\t\t\t\t\t\t</requireProperty>\n\t\t\t\t\t\t\t\t\t\t<enforceBytecodeVersion>\n\t\t\t\t\t\t\t\t\t\t\t<maxJdkVersion>${maven.compiler.source}</maxJdkVersion>\n\t\t\t\t\t\t\t\t\t\t</enforceBytecodeVersion>\n\t\t\t\t\t\t\t\t\t</rules>\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>org.codehaus.mojo</groupId>\n\t\t\t\t\t\t\t\t<artifactId>extra-enforcer-rules</artifactId>\n\t\t\t\t\t\t\t\t<version>1.8.0</version>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>deploy-settings</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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.sonatype.plugins</groupId>\n\t\t\t\t\t\t<artifactId>nexus-staging-maven-plugin</artifactId>\n\t\t\t\t\t\t<extensions>true</extensions>\n\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\tIn multi-module builds using the deploy-at-end feature,\n\t\t\t\t\t\t\tthe deployment of all components is performed in the last module based on the reactor order.\n\t\t\t\t\t\t\tIf this property is set to true in the last module,\n\t\t\t\t\t\t\tall staging deployment for all modules will be skipped.\n\t\t\t\t\t\t\tso, we'll config nexus deploy after every moudle's deploy phase\n\n\t\t\t\t\t\t\tsee: https://github.com/sonatype/nexus-maven-plugins/tree/master/staging/maven-plugin#configuring-the-plugin\n\t\t\t\t\t\t-->\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<serverId>ossrh</serverId>\n\t\t\t\t\t\t\t<nexusUrl>https://oss.sonatype.org/</nexusUrl>\n\t\t\t\t\t\t\t<autoReleaseAfterClose>true</autoReleaseAfterClose>\n\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\tIf you are deploying to Maven Central, it is the Nexus Staging Plugin that is\n\t\t\t\t\t\t\t\tdoing the deployment instead of the Deploy plugin,\n\t\t\t\t\t\t\t\tso the configuration of the deploy plugin has no effect.\n\t\t\t\t\t\t\t\tTo make the Nexus deploy plugin skip, set skipNexusStagingDeployMojo\n\t\t\t\t\t\t\t\tin its configuration to true.\n\n\t\t\t\t\t\t\t\tsee: https://stackoverflow.com/questions/59552549/preventing-maven-modules-from-being-deployed\n\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t<skipNexusStagingDeployMojo>${maven.deploy.skip}</skipNexusStagingDeployMojo>\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": "scripts/bump-ttl-version.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\n# adjust current dir to script dir\ncd \"$(dirname \"$(readlink -f \"$0\")\")\"\n\n# shellcheck disable=SC2154\n[ $# -ne 1 ] && cu::die \"need only 1 argument for version!$nl${nl}usage:$nl  $0 4.x.y\"\nreadonly bump_version=\"$1\"\n\ncd ..\n\necho \"bump TTL version of lib to $bump_version\"\n./mvnw versions:set \\\n  -DgenerateBackupPoms=false \\\n  -DprocessAllModules=true \\\n  -DnewVersion=\"$bump_version\"\n"
  },
  {
    "path": "scripts/check-japi-compliance.sh",
    "content": "#!/bin/bash\n# Java API Compliance Checker (JAPICC),\n# a tool for checking backward binary and source-level compatibility of a Java library API.\n#   https://github.com/lvc/japi-compliance-checker\nset -eEuo pipefail\ncd \"$(dirname \"$(readlink -f \"$0\")\")\"\n\n\nJCC=\"$(readlink -f \"$(command -v japi-compliance-checker.pl)\")\"\n\n\n\ncd ..\nmvn clean package\n\nttl_jar_path=$(echo \"target/transmittable-thread-local-\"*.jar)\n\nwork_dir=\"target/japi-compliance-checker\"\nmkdir -p $work_dir\ncd $work_dir\nrm -rf compat_reports\n\nfor base_version in 2.5.0 2.6.0 2.7.0 2.10.2; do\n    url=\"https://repo1.maven.org/maven2/com/alibaba/transmittable-thread-local/$base_version/transmittable-thread-local-$base_version.jar\"\n    base_jar=\"transmittable-thread-local-$base_version.jar\"\n    if [ ! -f \"$base_jar\" ]; then\n        cu::log_then_run wget --quiet \"$url\"\n    fi\n\n    \"$JCC\" -show-packages -check-annotations -skip-internal-packages '\\.(javassist|utils?|internal)(\\.|$)' \\\n        \"$base_jar\" \\\n        \"$ttl_jar_path\" || true\ndone\n"
  },
  {
    "path": "scripts/codecov.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\ncd \"$(dirname \"$(readlink -f \"$0\")\")\"\n\nsource bash-buddy/lib/trap_error_info.sh\nsource bash-buddy/lib/common_utils.sh\nsource bash-buddy/lib/prepare_jdks.sh\nsource bash-buddy/lib/java_build_utils.sh\n\ncd ..\n\nprepare_jdks::switch_to_jdk 8\n\n# about codecov: example-java-maven\n# https://github.com/codecov/example-java-maven/blob/master/.travis.yml\n\nif [ \"${1:-}\" = \"-s\" ]; then\n  jvb::mvn_cmd -Pgen-code-cov jacoco:prepare-agent surefire:test jacoco:report\nelse\n  jvb::mvn_cmd -Pgen-code-cov clean test\nfi\n\nbash <(curl -s https://codecov.io/bash)\n"
  },
  {
    "path": "scripts/integration-test.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\ncd \"$(dirname \"$(readlink -f \"$0\")\")\"\n\nBASH_BUDDY_ROOT=\"$(readlink -f bash-buddy)\"\nreadonly BASH_BUDDY_ROOT\nsource \"$BASH_BUDDY_ROOT/lib/trap_error_info.sh\"\nsource \"$BASH_BUDDY_ROOT/lib/common_utils.sh\"\nsource \"$BASH_BUDDY_ROOT/lib/java_utils.sh\"\nsource \"$BASH_BUDDY_ROOT/lib/maven_utils.sh\"\n\n################################################################################\n# ci build logic\n################################################################################\n\nreadonly default_build_jdk_version=17\n# shellcheck disable=SC2034\nreadonly JDK_VERSIONS=(\n  8\n  11\n  \"$default_build_jdk_version\"\n  21\n  22\n)\n\n# here use `install` and `-D performRelease` intended\n#   to check release operations.\n#\n# De-activate a maven profile from command line\n#   https://stackoverflow.com/questions/25201430\n#\n# shellcheck disable=SC2034\nreadonly MVU_MVN_OPTS=(\n  \"${MVU_DEFAULT_MVN_OPTS[@]}\"\n  -DperformRelease -P'!gen-sign'\n  # Maven Plugin Validation\n  # https://maven.apache.org/guides/plugins/validation/index.html\n  -Dmaven.plugin.validation=NONE\n  ${CI_MORE_MVN_OPTS:+${CI_MORE_MVN_OPTS}}\n)\n\ncd ..\n\n########################################\n# build and test by default version jdk\n########################################\n\njvu::switch_to_jdk \"$default_build_jdk_version\"\n\ncu::head_line_echo \"build and test with Java $default_build_jdk_version: $JAVA_HOME\"\nmvu::mvn_cmd clean install\n\n########################################\n# test by multi-version jdk\n########################################\n\n# about CI env var\n#   https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables\nif [ \"${CI:-}\" = true ]; then\n  readonly CI_MORE_BEGIN_OPTS=jacoco:prepare-agent CI_MORE_END_OPTS=jacoco:report\nfi\n\nfor jdk_version in \"${JDK_VERSIONS[@]}\"; do\n  jvu::switch_to_jdk \"$jdk_version\"\n\n  # just test without build\n  if [ \"$jdk_version\" != \"$default_build_jdk_version\" ]; then\n    # default jdk already tested above\n    cu::head_line_echo \"test with Java: $JAVA_HOME\"\n    mvu::mvn_cmd ${CI_MORE_BEGIN_OPTS:-} surefire:test -Denforcer.skip ${CI_MORE_END_OPTS:-}\n  fi\n\n  (\n    cd ttl2-compatible\n    cu::head_line_echo \"test with TTL Agent and Java: $JAVA_HOME\"\n\n    cu::blue_echo 'Run unit test under ttl agent, include check for ExecutorService, ForkJoinPool, Timer/TimerTask'\n    mvu::mvn_cmd ${CI_MORE_BEGIN_OPTS:-} \\\n      surefire:test -Denforcer.skip \\\n      -Penable-ttl-agent-for-test \\\n      -Dttl.agent.extra.d.options='-Drun-ttl-test-under-agent-with-enable-timer-task=true' \\\n      ${CI_MORE_END_OPTS:-}\n\n    cu::blue_echo 'Run unit test under ttl agent, and turn on the disable inheritable for thread pool enhancement'\n    mvu::mvn_cmd ${CI_MORE_BEGIN_OPTS:-} \\\n      surefire:test -Denforcer.skip \\\n      -Penable-ttl-agent-for-test \\\n      -Dttl.agent.extra.args='ttl.agent.disable.inheritable.for.thread.pool:true' \\\n      -Dttl.agent.extra.d.options='-Drun-ttl-test-under-agent-with-disable-inheritable=true' \\\n      ${CI_MORE_END_OPTS:-}\n\n    cu::blue_echo 'Run agent check for Timer/TimerTask, explicit \"ttl.agent.enable.timer.task\"'\n    mvu::mvn_cmd ${CI_MORE_BEGIN_OPTS:-} \\\n      surefire:test -Denforcer.skip \\\n      -Penable-ttl-agent-for-test \\\n      -Dttl.agent.extra.args='ttl.agent.enable.timer.task:true' \\\n      -Dttl.agent.extra.d.options='-Drun-ttl-test-under-agent-with-enable-timer-task=true' \\\n      ${CI_MORE_END_OPTS:-}\n  )\ndone\n"
  },
  {
    "path": "scripts/perf-test/memoryleak-ThreadLocal.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\ncd \"$(dirname \"$(readlink -f \"$0\")\")\"\n\ncd ../..\n\nreadonly mainClass=com.alibaba.perf.memoryleak.NoMemoryLeak_ThreadLocal_NoRemove\n\n./mvnw package exec:exec -DskipTests -Dexec.mainClass=\"$mainClass\"\n"
  },
  {
    "path": "scripts/perf-test/memoryleak-TransmittableThreadLocal.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\ncd \"$(dirname \"$(readlink -f \"$0\")\")\"\n\ncd ../..\n\nreadonly mainClass=com.alibaba.perf.memoryleak.NoMemoryLeak_TransmittableThreadLocal_NoRemove\n\n./mvnw package exec:exec -DskipTests -Dexec.mainClass=\"$mainClass\"\n"
  },
  {
    "path": "scripts/perf-test/tps-ThreadLocal.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\ncd \"$(dirname \"$(readlink -f \"$0\")\")\"\n\ncd ../..\n\nreadonly mainClass=com.alibaba.perf.tps.CreateThreadLocalInstanceTps\n\n./mvnw package exec:exec -DskipTests -Dexec.mainClass=\"$mainClass\"\n"
  },
  {
    "path": "scripts/perf-test/tps-TransmittableThreadLocal.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\ncd \"$(dirname \"$(readlink -f \"$0\")\")\"\n\ncd ../..\n\nreadonly mainClass=com.alibaba.perf.tps.CreateTransmittableThreadLocalInstanceTps\n\n./mvnw package exec:exec -DskipTests -Dexec.mainClass=\"$mainClass\"\n"
  },
  {
    "path": "scripts/release.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\ncd \"$(dirname \"$(readlink -f \"$0\")\")\"\nreadonly BASE=\"$(pwd)\"\n\nupdate_version=false\ndeploy_maven=false\ncreate_tag=false\ndeploy_java_doc=false\n\nwhile getopts \"djotv\" arg; do\n    case $arg in\n        v)\n            update_version=true\n            ;;\n        t)\n            create_tag=true\n            ;;\n        d)\n            deploy_maven=true\n            ;;\n        j)\n            deploy_java_doc=true\n            ;;\n        ?) # UNKNOWN option!\n            echo \"UNKNOWN option: $arg!\"\n            exit 1\n            ;;\n    esac\ndone\nshift $((OPTIND-1))\n\n\n\necho \"Current version is: $version\"\nnew_version=\"$(echo $version | sed 's/-SNAPSHOT//')\"\necho \"Use new version: $new_version\"\n\n\n$update_version && {\n    echo '================================================================================'\n    echo \"Update version!\"\n    echo '================================================================================'\n\n    # update pom version\n    echo \"update pom version...\"\n    find -name pom.xml | xargs sed \"s/$version/$new_version/\" -i\n    # update version in docs\n    echo \"update badges link in docs...\"\n    find -name '*.md' -a -not -name 'release-action-list.md' | xargs sed \"s/master/v$new_version/g\" -i\n    echo \"update maven dependency version in docs...\"\n    sed \"s#<version>.*</version>#<version>$new_version</version>#\" -i *.md\n\n    $create_tag && {\n        git add -A\n        git commit -m \"release v$new_version\"\n        git tag -a \"v$new_version\" -m \"release v$new_version\" -f\n        git push origin \"v$new_version\" -f\n    }\n}\n\n$deploy_maven && {\n    echo '================================================================================'\n    echo 'deploy to maven center repo...'\n    echo '================================================================================'\n    ./mvnw deploy -DperformRelease=true\n}\n\n\n$deploy_java_doc && {\n    ./mvnw install -Dmaven.test.skip=true -PsrcDoc\n\n    git checkout gh-pages\n    mv target/apidocs \"apidocs/$new_version\"\n    sed \"s#\\\".*/index.html\\\"#\\\"$new_version/index.html\\\"#\" -i apidocs/index.html\n\n    git add -A\n    git commit -m \"add javadoc for $new_version\"\n    git push\n}\n"
  },
  {
    "path": "scripts/run-agent-demo.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\ncd \"$(dirname \"$(readlink -f \"$0\")\")\"\n\ncd ..\n\nreadonly mainClass=${1:-com.alibaba.demo.ttl.agent.AgentDemo}\n\n./mvnw -Penable-ttl-agent-for-test \\\n  package exec:exec \\\n  -DskipTests \\\n  -Dexec.mainClass=\"$mainClass\"\n"
  },
  {
    "path": "src/package-list/java/package-list",
    "content": "com.sun.jarsigner\ncom.sun.java.accessibility.util\ncom.sun.javadoc\ncom.sun.jdi\ncom.sun.jdi.connect\ncom.sun.jdi.connect.spi\ncom.sun.jdi.event\ncom.sun.jdi.request\ncom.sun.management\ncom.sun.net.httpserver\ncom.sun.net.httpserver.spi\ncom.sun.nio.sctp\ncom.sun.security.auth\ncom.sun.security.auth.callback\ncom.sun.security.auth.login\ncom.sun.security.auth.module\ncom.sun.security.jgss\ncom.sun.source.doctree\ncom.sun.source.tree\ncom.sun.source.util\ncom.sun.tools.attach\ncom.sun.tools.attach.spi\ncom.sun.tools.doclets\ncom.sun.tools.doclets.standard\ncom.sun.tools.javac\ncom.sun.tools.javadoc\ncom.sun.tools.jconsole\njava.applet\njava.awt\njava.awt.color\njava.awt.datatransfer\njava.awt.desktop\njava.awt.dnd\njava.awt.event\njava.awt.font\njava.awt.geom\njava.awt.im\njava.awt.im.spi\njava.awt.image\njava.awt.image.renderable\njava.awt.print\njava.beans\njava.beans.beancontext\njava.io\njava.lang\njava.lang.annotation\njava.lang.instrument\njava.lang.invoke\njava.lang.management\njava.lang.module\njava.lang.ref\njava.lang.reflect\njava.math\njava.net\njava.net.spi\njava.nio\njava.nio.channels\njava.nio.channels.spi\njava.nio.charset\njava.nio.charset.spi\njava.nio.file\njava.nio.file.attribute\njava.nio.file.spi\njava.rmi\njava.rmi.activation\njava.rmi.dgc\njava.rmi.registry\njava.rmi.server\njava.security\njava.security.acl\njava.security.cert\njava.security.interfaces\njava.security.spec\njava.sql\njava.text\njava.text.spi\njava.time\njava.time.chrono\njava.time.format\njava.time.temporal\njava.time.zone\njava.util\njava.util.concurrent\njava.util.concurrent.atomic\njava.util.concurrent.locks\njava.util.function\njava.util.jar\njava.util.logging\njava.util.prefs\njava.util.regex\njava.util.spi\njava.util.stream\njava.util.zip\njavafx.animation\njavafx.application\njavafx.beans\njavafx.beans.binding\njavafx.beans.property\njavafx.beans.property.adapter\njavafx.beans.value\njavafx.collections\njavafx.collections.transformation\njavafx.concurrent\njavafx.css\njavafx.css.converter\njavafx.embed.swing\njavafx.event\njavafx.fxml\njavafx.geometry\njavafx.print\njavafx.scene\njavafx.scene.canvas\njavafx.scene.chart\njavafx.scene.control\njavafx.scene.control.cell\njavafx.scene.control.skin\njavafx.scene.effect\njavafx.scene.image\njavafx.scene.input\njavafx.scene.layout\njavafx.scene.media\njavafx.scene.paint\njavafx.scene.shape\njavafx.scene.text\njavafx.scene.transform\njavafx.scene.web\njavafx.stage\njavafx.util\njavafx.util.converter\njavax.accessibility\njavax.activation\njavax.activity\njavax.annotation\njavax.annotation.processing\njavax.crypto\njavax.crypto.interfaces\njavax.crypto.spec\njavax.imageio\njavax.imageio.event\njavax.imageio.metadata\njavax.imageio.plugins.bmp\njavax.imageio.plugins.jpeg\njavax.imageio.plugins.tiff\njavax.imageio.spi\njavax.imageio.stream\njavax.jnlp\njavax.jws\njavax.jws.soap\njavax.lang.model\njavax.lang.model.element\njavax.lang.model.type\njavax.lang.model.util\njavax.management\njavax.management.loading\njavax.management.modelmbean\njavax.management.monitor\njavax.management.openmbean\njavax.management.relation\njavax.management.remote\njavax.management.remote.rmi\njavax.management.timer\njavax.naming\njavax.naming.directory\njavax.naming.event\njavax.naming.ldap\njavax.naming.spi\njavax.net\njavax.net.ssl\njavax.print\njavax.print.attribute\njavax.print.attribute.standard\njavax.print.event\njavax.rmi\njavax.rmi.CORBA\njavax.rmi.ssl\njavax.script\njavax.security.auth\njavax.security.auth.callback\njavax.security.auth.kerberos\njavax.security.auth.login\njavax.security.auth.spi\njavax.security.auth.x500\njavax.security.cert\njavax.security.sasl\njavax.smartcardio\njavax.sound.midi\njavax.sound.midi.spi\njavax.sound.sampled\njavax.sound.sampled.spi\njavax.sql\njavax.sql.rowset\njavax.sql.rowset.serial\njavax.sql.rowset.spi\njavax.swing\njavax.swing.border\njavax.swing.colorchooser\njavax.swing.event\njavax.swing.filechooser\njavax.swing.plaf\njavax.swing.plaf.basic\njavax.swing.plaf.metal\njavax.swing.plaf.multi\njavax.swing.plaf.nimbus\njavax.swing.plaf.synth\njavax.swing.table\njavax.swing.text\njavax.swing.text.html\njavax.swing.text.html.parser\njavax.swing.text.rtf\njavax.swing.tree\njavax.swing.undo\njavax.tools\njavax.transaction\njavax.transaction.xa\njavax.xml\njavax.xml.bind\njavax.xml.bind.annotation\njavax.xml.bind.annotation.adapters\njavax.xml.bind.attachment\njavax.xml.bind.helpers\njavax.xml.bind.util\njavax.xml.catalog\njavax.xml.crypto\njavax.xml.crypto.dom\njavax.xml.crypto.dsig\njavax.xml.crypto.dsig.dom\njavax.xml.crypto.dsig.keyinfo\njavax.xml.crypto.dsig.spec\njavax.xml.datatype\njavax.xml.namespace\njavax.xml.parsers\njavax.xml.soap\njavax.xml.stream\njavax.xml.stream.events\njavax.xml.stream.util\njavax.xml.transform\njavax.xml.transform.dom\njavax.xml.transform.sax\njavax.xml.transform.stax\njavax.xml.transform.stream\njavax.xml.validation\njavax.xml.ws\njavax.xml.ws.handler\njavax.xml.ws.handler.soap\njavax.xml.ws.http\njavax.xml.ws.soap\njavax.xml.ws.spi\njavax.xml.ws.spi.http\njavax.xml.ws.wsaddressing\njavax.xml.xpath\njdk.dynalink\njdk.dynalink.beans\njdk.dynalink.linker\njdk.dynalink.linker.support\njdk.dynalink.support\njdk.incubator.http\njdk.javadoc.doclet\njdk.jfr\njdk.jfr.consumer\njdk.jshell\njdk.jshell.execution\njdk.jshell.spi\njdk.jshell.tool\njdk.management.cmm\njdk.management.jfr\njdk.management.resource\njdk.nashorn.api.scripting\njdk.nashorn.api.tree\njdk.net\njdk.packager.services\njdk.security.jarsigner\nnetscape.javascript\norg.ietf.jgss\norg.omg.CORBA\norg.omg.CORBA_2_3\norg.omg.CORBA_2_3.portable\norg.omg.CORBA.DynAnyPackage\norg.omg.CORBA.ORBPackage\norg.omg.CORBA.portable\norg.omg.CORBA.TypeCodePackage\norg.omg.CosNaming\norg.omg.CosNaming.NamingContextExtPackage\norg.omg.CosNaming.NamingContextPackage\norg.omg.Dynamic\norg.omg.DynamicAny\norg.omg.DynamicAny.DynAnyFactoryPackage\norg.omg.DynamicAny.DynAnyPackage\norg.omg.IOP\norg.omg.IOP.CodecFactoryPackage\norg.omg.IOP.CodecPackage\norg.omg.Messaging\norg.omg.PortableInterceptor\norg.omg.PortableInterceptor.ORBInitInfoPackage\norg.omg.PortableServer\norg.omg.PortableServer.CurrentPackage\norg.omg.PortableServer.POAManagerPackage\norg.omg.PortableServer.POAPackage\norg.omg.PortableServer.portable\norg.omg.PortableServer.ServantLocatorPackage\norg.omg.SendingContext\norg.omg.stub.java.rmi\norg.w3c.dom\norg.w3c.dom.bootstrap\norg.w3c.dom.css\norg.w3c.dom.events\norg.w3c.dom.html\norg.w3c.dom.ls\norg.w3c.dom.ranges\norg.w3c.dom.stylesheets\norg.w3c.dom.traversal\norg.w3c.dom.views\norg.w3c.dom.xpath\norg.xml.sax\norg.xml.sax.ext\norg.xml.sax.helpers\n"
  },
  {
    "path": "src/package-list/jetbrains-annotations/package-list",
    "content": "org.intellij.lang.annotations\norg.jetbrains.annotations\n"
  },
  {
    "path": "src/package-list/jsr305/package-list",
    "content": "javax.annotation\njavax.annotation.concurrent\njavax.annotation.meta\n"
  },
  {
    "path": "src/package-list/spotbugs-annotations/package-list",
    "content": "edu.umd.cs.findbugs.annotations\n"
  },
  {
    "path": "ttl-agent/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.ttl3</groupId>\n\t\t<artifactId>ttl3-parent</artifactId>\n\t\t<version>3.x-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\n\t<artifactId>ttl-agent</artifactId>\n\t<packaging>jar</packaging>\n\t<name>TransmittableThreadLocal(TTL) Agent</name>\n\t<description>${project.name}</description>\n\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t<inceptionYear>2022</inceptionYear>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache 2</name>\n\t\t\t<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t\t<comments>A business-friendly OSS license</comments>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<connection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</connection>\n\t\t<developerConnection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</developerConnection>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t</scm>\n\t<issueManagement>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/issues</url>\n\t\t<system>GitHub Issues</system>\n\t</issueManagement>\n\t<ciManagement>\n\t\t<system>GitHub Actions</system>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/actions</url>\n\t</ciManagement>\n\t<organization>\n\t\t<name>Alibaba</name>\n\t\t<url>https://www.alibaba.com</url>\n\t</organization>\n\t<developers>\n\t\t<developer>\n\t\t\t<name>Jerry Lee</name>\n\t\t\t<id>oldratlee</id>\n\t\t\t<email>oldratlee(AT)gmail(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/oldratlee</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<name>wuwen</name>\n\t\t\t<id>wuwen5</id>\n\t\t\t<email>wuwen.55(AT)aliyun(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/wuwen5</url>\n\t\t\t<organization>ofpay</organization>\n\t\t\t<organizationUrl>https://www.ofpay.com</organizationUrl>\n\t\t</developer>\n\t</developers>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.ttl3</groupId>\n\t\t\t<artifactId>ttl-core</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.javassist</groupId>\n\t\t\t<artifactId>javassist</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<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\tInstrumentation Specification\n\t\t\t\t\t\t\t\t\t- https://docs.oracle.com/javase/8/docs/technotes/guides/instrumentation/index.html (this doc for java 8)\n\t\t\t\t\t\t\t\t\t- https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html#package.description\n\t\t\t\t\t\t\t\tJAR Manifest - JAR File Specification\n\t\t\t\t\t\t\t\t\t- https://docs.oracle.com/en/java/javase/21/docs/specs/jar/jar.html#jar-manifest\n\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t<Premain-Class>com.alibaba.ttl3.agent.TtlAgent</Premain-Class>\n\t\t\t\t\t\t\t<Boot-Class-Path>${project.build.finalName}.jar</Boot-Class-Path>\n\t\t\t\t\t\t\t<Can-Redefine-Classes>false</Can-Redefine-Classes>\n\t\t\t\t\t\t\t<Can-Retransform-Classes>true</Can-Retransform-Classes>\n\t\t\t\t\t\t\t<Can-Set-Native-Method-Prefix>false</Can-Set-Native-Method-Prefix>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<artifactId>maven-shade-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>shade-when-package</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>shade</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<relocations>\n\t\t\t\t\t\t\t\t<!-- https://maven.apache.org/plugins/maven-shade-plugin/examples/class-relocation.html -->\n\t\t\t\t\t\t\t\t<relocation>\n\t\t\t\t\t\t\t\t\t<pattern>javassist</pattern>\n\t\t\t\t\t\t\t\t\t<shadedPattern>com.alibaba.ttl3.agent.transformlet.javassist</shadedPattern>\n\t\t\t\t\t\t\t\t</relocation>\n\t\t\t\t\t\t\t</relocations>\n\t\t\t\t\t\t\t<artifactSet>\n\t\t\t\t\t\t\t\t<includes>\n\t\t\t\t\t\t\t\t\t<include>org.javassist:javassist</include>\n\t\t\t\t\t\t\t\t\t<include>com.alibaba.ttl3:ttl-core</include>\n\t\t\t\t\t\t\t\t</includes>\n\t\t\t\t\t\t\t</artifactSet>\n\t\t\t\t\t\t\t<filters>\n\t\t\t\t\t\t\t\t<filter>\n\t\t\t\t\t\t\t\t\t<artifact>org.javassist:javassist</artifact>\n\t\t\t\t\t\t\t\t\t<excludes>\n\t\t\t\t\t\t\t\t\t\t<exclude>META-INF/MANIFEST.MF</exclude>\n\t\t\t\t\t\t\t\t\t</excludes>\n\t\t\t\t\t\t\t\t</filter>\n\t\t\t\t\t\t\t\t<filter>\n\t\t\t\t\t\t\t\t\t<artifact>com.alibaba.ttl3:ttl-core</artifact>\n\t\t\t\t\t\t\t\t\t<excludes>\n\t\t\t\t\t\t\t\t\t\t<exclude>com/alibaba/ttl3/agent/package-info.class</exclude>\n\t\t\t\t\t\t\t\t\t\t<exclude>com/alibaba/ttl3/agent/package-info.java</exclude>\n\t\t\t\t\t\t\t\t\t\t<exclude>META-INF/MANIFEST.MF</exclude>\n\t\t\t\t\t\t\t\t\t</excludes>\n\t\t\t\t\t\t\t\t</filter>\n\t\t\t\t\t\t\t</filters>\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</plugin>\n\t\t</plugins>\n\t</build>\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>config-for-jdk16+</id>\n\t\t\t<activation>\n\t\t\t\t<jdk>[16,)</jdk>\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<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludes>\n\t\t\t\t\t\t\t\t<exclude>**/*$*</exclude>\n\t\t\t\t\t\t\t\t<exclude>**/JavassistTest*</exclude>\n\t\t\t\t\t\t\t</excludes>\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>enable-ttl-agent-for-test</id>\n\t\t\t<properties>\n\t\t\t\t<!-- https://maven.apache.org/plugins/maven-jar-plugin/jar-mojo.html -->\n\t\t\t\t<ttl.built.agent.jar>\n\t\t\t\t\t${project.build.directory}/${project.artifactId}-${project.version}.jar\n\t\t\t\t</ttl.built.agent.jar>\n\t\t\t\t<ttl.agent.args>ttl.agent.logger:STDOUT</ttl.agent.args>\n\t\t\t\t<ttl.agent.extra.args/> <!-- overridden by maven -D options -->\n\t\t\t\t<ttl.agent.extra.d.options/> <!-- overridden by maven -D options -->\n\t\t\t\t<ttl.agent.jvm.arg>-javaagent:${ttl.built.agent.jar}=${ttl.agent.args},${ttl.agent.extra.args}</ttl.agent.jvm.arg>\n\t\t\t\t<ttl.agent.jvm.args>\n\t\t\t\t\t-Drun-ttl-test-under-agent=true ${ttl.agent.extra.d.options} ${ttl.agent.jvm.arg}\n\t\t\t\t</ttl.agent.jvm.args>\n\t\t\t\t<exec.mainClass>com.alibaba.demo.ttl.agent.AgentDemo</exec.mainClass> <!-- overridden by maven -D options -->\n\t\t\t</properties>\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<!--\n\t\t\t\t\t\t\treference: https://github.com/EMResearch/EvoMaster/blob/95163fb042101a71289c17f6e433f91fc1f868ef/pom.xml#L851\n\t\t\t\t\t\t-->\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<forkCount>1</forkCount>\n\t\t\t\t\t\t\t<redirectTestOutputToFile>true</redirectTestOutputToFile>\n\t\t\t\t\t\t\t<classpathDependencyExcludes>\n\t\t\t\t\t\t\t\t<classpathDependencyExclude>org.javassist:javassist</classpathDependencyExclude>\n\t\t\t\t\t\t\t\t<classpathDependencyExclude>com.github.spotbugs:spotbugs-annotations</classpathDependencyExclude>\n\t\t\t\t\t\t\t\t<classpathDependencyExclude>com.google.code.findbugs:jsr305</classpathDependencyExclude>\n\t\t\t\t\t\t\t\t<classpathDependencyExclude>org.jetbrains:annotations</classpathDependencyExclude>\n\t\t\t\t\t\t\t</classpathDependencyExcludes>\n\t\t\t\t\t\t\t<argLine>@{argLine} ${ttl.agent.jvm.args}</argLine>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\thttps://www.mojohaus.org/exec-maven-plugin/examples/example-exec-for-java-programs.html\n\t\t\t\t\t\t-->\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<configuration>\n\t\t\t\t\t\t\t<arguments>\n\t\t\t\t\t\t\t\t<argument>-Xmx1g</argument>\n\t\t\t\t\t\t\t\t<argument>-Xms256m</argument>\n\t\t\t\t\t\t\t\t<argument>-ea</argument>\n\t\t\t\t\t\t\t\t<argument>-server</argument>\n\t\t\t\t\t\t\t\t<argument>-Duser.language=en</argument>\n\t\t\t\t\t\t\t\t<argument>-Duser.country=US</argument>\n\n\t\t\t\t\t\t\t\t<argument>${ttl.agent.jvm.arg}</argument>\n\n\t\t\t\t\t\t\t\t<argument>-classpath</argument>\n\t\t\t\t\t\t\t\t<classpath/>\n\n\t\t\t\t\t\t\t\t<argument>${exec.mainClass}</argument>\n\t\t\t\t\t\t\t</arguments>\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>gen-src</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<attach>false</attach>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<artifactId>maven-shade-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>shade-when-package</id>\n\t\t\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t\t\t<createSourcesJar>true</createSourcesJar>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>gen-api-doc</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\n\t\t\t</activation>\n\t\t\t<properties>\n\t\t\t\t<javadoc.extra.offlineLinks>-linkoffline ${javadoc.ttl.base.link}/ttl-core/ ${project.basedir}/../ttl-core/target/apidocs/</javadoc.extra.offlineLinks>\n\t\t\t</properties>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/TtlAgent.java",
    "content": "package com.alibaba.ttl3.agent;\n\nimport com.alibaba.ttl3.agent.logging.Logger;\nimport com.alibaba.ttl3.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl3.agent.transformlet.internal.ForkJoinTtlTransformlet;\nimport com.alibaba.ttl3.agent.transformlet.internal.JdkExecutorTtlTransformlet;\nimport com.alibaba.ttl3.agent.transformlet.internal.PriorityBlockingQueueTtlTransformlet;\nimport com.alibaba.ttl3.agent.transformlet.internal.TimerTaskTtlTransformlet;\nimport com.alibaba.ttl3.executor.TtlExecutors;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.lang.instrument.ClassFileTransformer;\nimport java.lang.instrument.Instrumentation;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * TTL Java Agent.\n *\n * <h2>The configuration for TTL agent</h2>\n * <p>\n * Configure TTL agent via {@code -D property}({@link System#getProperties()}) or TTL agent arguments.\n * <ol>\n *     <li>{@code -D property} config format is: {@code -Dkey1=v2 -Dkey2=v2}</li>\n *     <li>TTL agent arguments config format is {@code key1:v1,key2:v2}.<br>\n *         separate key-value pairs by {@code char ,}, and separate key-value by {@code char :}.<br></li>\n * </ol>\n * <B><I>NOTE about the config sources and the precedence:</I></B><br>\n * <ol>\n * <li>Read {@code -D property}({@link System#getProperties()}) first.</li>\n * <li>if no {@code -D property} configured(including empty property value configured by {@code -Dkey1}/{@code -Dkey1=}), read TTL Agent argument configuration.</li>\n * </ol>\n * Below is available TTL agent configuration keys.\n *\n * <h3>Configuration key: Log Type</h3>\n * <p>\n * The log type of TTL Java Agent is configured by key {@code ttl.agent.logger}. Since version {@code 2.6.0}.\n *\n * <ul>\n * <li>{@code ttl.agent.logger : STDERR}<br>\n * only log to {@code stderr} when error.\n * This is <b>default</b>, when no/unrecognized configuration for key {@code ttl.agent.logger}.</li>\n * <li>{@code ttl.agent.logger : STDOUT}<br>\n * Log to {@code stdout}, more info than {@code ttl.agent.logger:STDERR}; This is needed when developing.</li>\n * </ul>\n * <p>\n * Configuration example:\n *\n * <ol>\n * <li>{@code -Dttl.agent.logger=STDOUT}</li>\n * <li>{@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT}</li>\n * </ol>\n *\n * <h3>Configuration key: Disable inheritable for thread pool</h3>\n * <p>\n * Enable \"disable inheritable\" for thread pool, configured by key {@code ttl.agent.disable.inheritable.for.thread.pool}.\n * When no configuration for this key, default is {@code false}(aka. do <b>NOT</b> disable inheritable). Since version {@code 2.10.1}.\n *\n * <ul>\n * <li>rewrite the {@link java.util.concurrent.ThreadFactory} constructor parameter\n * of {@link java.util.concurrent.ThreadPoolExecutor}\n * to {@code DisableInheritableThreadFactory}\n * by util method {@link TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory) getDisableInheritableThreadFactory}.\n * </li>\n * <li>rewrite the {@link java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory} constructor parameter\n * of {@link java.util.concurrent.ForkJoinPool}\n * to {@code DisableInheritableForkJoinWorkerThreadFactory}\n * by util method {@link TtlExecutors#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory) getDisableInheritableForkJoinWorkerThreadFactory}.\n * </li>\n * </ul>\n * More info about \"disable inheritable\" see {@link com.alibaba.ttl3.TransmittableThreadLocal}.\n * <p>\n * Configuration example:\n *\n * <ol>\n * <li>{@code -Dttl.agent.disable.inheritable.for.thread.pool=true}</li>\n * <li>{@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.disable.inheritable.for.thread.pool:true}</li>\n * </ol>\n *\n * <h3>Configuration key: Enable TimerTask class decoration</h3>\n * <p>\n * Enable TimerTask class decoration is configured by key {@code ttl.agent.enable.timer.task}.\n * Since version {@code 2.7.0}.\n * <p>\n * When no configuration for this key, default is {@code true}(aka. <b>enabled</b>).<br>\n * <b><i>Note</i></b>: Since version {@code 2.11.2} the default value is {@code true}(enable TimerTask class decoration);\n * Before version {@code 2.11.1} default value is {@code false}.\n * <p>\n * Configuration example:\n *\n * <ol>\n * <li>{@code -Dttl.agent.enable.timer.task=false}</li>\n * <li>{@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:false}</li>\n * </ol>\n *\n * <h3>Configuration key: logging the transform class received by TTL Agent</h3>\n * <p>\n * Enable logging the transform class received by TTL Agent by key {@code ttl.agent.log.class.transform},\n * default is {@code false}(aka. do <b>NOT</b> logging the transform class received by TTL Agent).\n * Since version {@code 3.0.0}.\n * <p>\n * Configuration example:\n *\n * <ol>\n * <li>{@code -Dttl.agent.log.class.transform=true}</li>\n * <li>{@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.log.class.transform:true}</li>\n * </ol>\n *\n * <h3>Multi key configuration example</h3>\n * <p>\n * For {@code -D property} config, simply specify multiply {@code -D property}, example:<br>\n * {@code -Dttl.agent.logger=STDOUT -Dttl.agent.disable.inheritable.for.thread.pool=true}\n * <p>\n * For TTL agent arguments config, example:<br>\n * {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT,ttl.agent.disable.inheritable.for.thread.pool:true}\n *\n * <h2>About boot classpath for TTL agent</h2>\n * <p>\n * <b><i>NOTE:</i></b> Since {@code v2.6.0}, TTL agent jar will auto add self to {@code boot classpath}.<br>\n * But you <b>should <i>NOT</i></b> modify the downloaded TTL jar file name in the maven repo(eg: {@code transmittable-thread-local-2.x.y.jar}).<br>\n * if you modified the downloaded TTL agent jar file name(eg: {@code ttl-foo-name-changed.jar}),\n * you must add TTL agent jar to {@code boot classpath} manually\n * by java option {@code -Xbootclasspath/a:path/to/ttl-foo-name-changed.jar}.\n * <p>\n * The implementation of auto adding self agent jar to {@code boot classpath} use\n * the {@code Boot-Class-Path} property of manifest file({@code META-INF/MANIFEST.MF}) in the TTL Java Agent Jar:\n *\n * <blockquote>\n * <dl>\n * <dt>Boot-Class-Path</dt>\n * <dd>\n * A list of paths to be searched by the bootstrap class loader. Paths represent directories or libraries (commonly referred to as JAR or zip libraries on many platforms).\n * These paths are searched by the bootstrap class loader after the platform specific mechanisms of locating a class have failed. Paths are searched in the order listed.\n * </dd>\n * </dl>\n * </blockquote>\n * <p>\n * More info about {@code Boot-Class-Path} see\n * <a href=\"https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html\">The mechanism for instrumentation</a>.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see Instrumentation\n * @see <a href=\"https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html\">The mechanism for instrumentation</a>\n * @see <a href=\"https://docs.oracle.com/en/java/javase/21/docs/specs/jar/jar.html#jar-manifest\">JAR File Specification - JAR Manifest</a>\n * @see <a href=\"https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html\">Working with Manifest Files - The Java™ Tutorials</a>\n * @see com.alibaba.ttl3.TransmittableThreadLocal\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ScheduledThreadPoolExecutor\n * @see java.util.concurrent.ForkJoinPool\n * @see TtlExecutors#getDefaultDisableInheritableThreadFactory()\n * @see TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)\n * @see TtlExecutors#getDefaultDisableInheritableForkJoinWorkerThreadFactory()\n * @see TtlExecutors#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory)\n * @see java.util.TimerTask\n */\npublic final class TtlAgent implements TtlAgentStatus {\n\n    /**\n     * the TTL agent configuration key: Log Type\n     *\n     * @see TtlAgent\n     */\n    public static final String TTL_AGENT_LOGGER_KEY = \"ttl.agent.logger\";\n\n    /**\n     * the TTL agent configuration key: Disable inheritable for thread pool\n     *\n     * @see TtlAgent\n     */\n    public static final String TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY = \"ttl.agent.disable.inheritable.for.thread.pool\";\n\n    /**\n     * the TTL agent configuration key: Enable TimerTask class decoration\n     *\n     * @see TtlAgent\n     */\n    public static final String TTL_AGENT_ENABLE_TIMER_TASK_KEY = \"ttl.agent.enable.timer.task\";\n\n    /**\n     * the TTL agent configuration key: logging the transform class received by TTL Agent\n     *\n     * @see TtlAgent\n     */\n    public static final String TTL_AGENT_LOG_CLASS_TRANSFORM_KEY = \"ttl.agent.log.class.transform\";\n\n\n    // ======== TTL Agent internal States ========\n\n    private static volatile Map<String, String> kvs;\n\n    private static volatile boolean ttlAgentLoaded = false;\n\n    /**\n     * Entrance method of TTL Java Agent.\n     *\n     * @see TtlAgent\n     */\n    public static void premain(final String agentArgs, @NonNull final Instrumentation inst) {\n        kvs = TtlAgentHelper.splitCommaColonStringToKV(agentArgs);\n\n        Logger.setLoggerImplType(getLoggerType());\n        final Logger logger = Logger.getLogger(TtlAgent.class);\n\n        try {\n            logger.info(\"[TtlAgent.premain] begin, agentArgs: \" + agentArgs + \", Instrumentation: \" + inst);\n\n            logger.info(logTtlAgentConfig());\n\n            final List<TtlTransformlet> transformletList = new ArrayList<>();\n\n            transformletList.add(new JdkExecutorTtlTransformlet());\n            transformletList.add(new PriorityBlockingQueueTtlTransformlet());\n\n            transformletList.add(new ForkJoinTtlTransformlet());\n\n            if (isEnableTimerTask()) transformletList.add(new TimerTaskTtlTransformlet());\n\n            final ClassFileTransformer transformer = new TtlTransformer(transformletList, isLogClassTransform());\n            inst.addTransformer(transformer, true);\n            logger.info(\"[TtlAgent.premain] add Transformer \" + transformer.getClass().getName() + \" success\");\n\n            logger.info(\"[TtlAgent.premain] end\");\n\n            ttlAgentLoaded = true;\n        } catch (Exception e) {\n            String msg = \"Fail to load TtlAgent , cause: \" + e.toString();\n            logger.error(msg, e);\n            throw new IllegalStateException(msg, e);\n        }\n    }\n\n    private static String logTtlAgentConfig() {\n        return \"TTL Agent configurations:\"\n                + \"\\n    \" + TTL_AGENT_LOGGER_KEY + \"=\" + getLoggerType()\n                + \"\\n    \" + TTL_AGENT_LOG_CLASS_TRANSFORM_KEY + \"=\" + isLogClassTransform()\n                + \"\\n    \" + TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY + \"=\" + isDisableInheritableForThreadPool()\n                + \"\\n    \" + TTL_AGENT_ENABLE_TIMER_TASK_KEY + \"=\" + isEnableTimerTask();\n    }\n\n    /**\n     * Whether TTL agent is loaded.\n     */\n    public boolean isTtlAgentLoaded() {\n        return ttlAgentLoaded;\n    }\n\n    /**\n     * Whether disable inheritable for thread pool is enhanced by ttl agent, check {@link #isTtlAgentLoaded()} first.\n     * <p>\n     * Same as {@code isBooleanOptionSet(TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY)}.\n     *\n     * @see TtlExecutors#getDefaultDisableInheritableThreadFactory()\n     * @see TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)\n     * @see TtlExecutors#getDefaultDisableInheritableForkJoinWorkerThreadFactory()\n     * @see TtlExecutors#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory)\n     * @see com.alibaba.ttl3.TransmittableThreadLocal\n     * @see TtlAgent\n     * @see #isBooleanOptionSet(String)\n     * @see #TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY\n     */\n    public static boolean isDisableInheritableForThreadPool() {\n        return isBooleanOptionSet(TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY);\n    }\n\n    /**\n     * Whether timer task is enhanced by ttl agent, check {@link #isTtlAgentLoaded()} first.\n     * <p>\n     * Same as {@code isBooleanOptionSet(TTL_AGENT_ENABLE_TIMER_TASK_KEY, true)}.\n     *\n     * @see java.util.Timer\n     * @see java.util.TimerTask\n     * @see TtlAgent\n     * @see #isBooleanOptionSet(String, boolean)\n     * @see #TTL_AGENT_ENABLE_TIMER_TASK_KEY\n     */\n    public static boolean isEnableTimerTask() {\n        return isBooleanOptionSet(TTL_AGENT_ENABLE_TIMER_TASK_KEY, true);\n    }\n\n    /**\n     * Whether logging the transform class received by {@link TtlAgent}.\n     * <p>\n     * Same as {@code isBooleanOptionSet(TTL_AGENT_LOG_CLASS_TRANSFORM_KEY)}.\n     *\n     * @see TtlAgent\n     * @see #isBooleanOptionSet(String)\n     * @see #TTL_AGENT_LOG_CLASS_TRANSFORM_KEY\n     */\n    public static boolean isLogClassTransform() {\n        return isBooleanOptionSet(TTL_AGENT_LOG_CLASS_TRANSFORM_KEY);\n    }\n\n    /**\n     * Get the TTL Agent Log type.\n     * <p>\n     * Same as {@code getStringOptionValue(TTL_AGENT_LOGGER_KEY, Logger.STDERR)}.\n     *\n     * @see Logger\n     * @see Logger#STDERR\n     * @see Logger#STDOUT\n     * @see TtlAgent\n     * @see #getStringOptionValue(String, String)\n     * @see #TTL_AGENT_LOGGER_KEY\n     */\n    @NonNull\n    public static String getLoggerType() {\n        return getStringOptionValue(TTL_AGENT_LOGGER_KEY, Logger.STDERR);\n    }\n\n    // ======== Generic Option Getters ========\n\n    /**\n     * Generic Option Getters for {@code boolean type} option.\n     * <p>\n     * Same as {@code isBooleanOptionSet(key, false)}.\n     *\n     * @see #isBooleanOptionSet(String, boolean)\n     * @see TtlAgent\n     */\n    public static boolean isBooleanOptionSet(@NonNull String key) {\n        return isBooleanOptionSet(key, false);\n    }\n\n    /**\n     * Generic Option Getters for {@code boolean type} option.\n     *\n     * @see TtlAgent\n     */\n    public static boolean isBooleanOptionSet(@NonNull String key, boolean defaultValueIfKeyAbsent) {\n        return TtlAgentHelper.isBooleanOptionSet(kvs, key, defaultValueIfKeyAbsent);\n    }\n\n    /**\n     * Generic Option Getters for {@code string type} option.\n     * <p>\n     * usage example:\n     * <p>\n     * if {@code -Dttl.agent.logger=STDOUT} or\n     * TTL Agent configuration is {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT},\n     * {@code getOptionValue(\"ttl.agent.logger\")} return {@code STDOUT}.\n     *\n     * @see TtlAgent\n     */\n    @NonNull\n    public static String getStringOptionValue(@NonNull String key, @NonNull String defaultValue) {\n        return TtlAgentHelper.getStringOptionValue(kvs, key, defaultValue);\n    }\n\n    /**\n     * Generic Option Getters for {@code string list type} option.\n     * <p>\n     * TTL configuration use {@code |} to separate items.\n     * <p>\n     * usage example:<br>\n     * if {@code -Dfoo.list=v1|v2|v3} or\n     * TTL Agent configuration is {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=foo.list:v1|v2|v3},\n     * {@code getOptionValue(\"foo.list\")} return {@code [v1, v2, v3]}.\n     *\n     * @see TtlAgent\n     */\n    @NonNull\n    static List<String> getOptionStringListValues(@NonNull String key) {\n        return TtlAgentHelper.getOptionStringListValues(kvs, key);\n    }\n\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlAgent() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/TtlAgentHelper.java",
    "content": "package com.alibaba.ttl3.agent;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.util.*;\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfinal class TtlAgentHelper {\n\n    // ======== Option Getter Methods ========\n\n    static boolean isBooleanOptionSet(\n            @Nullable final Map<String, String> kvs, @NonNull String key,\n            boolean defaultValueIfKeyAbsent\n    ) {\n        return isBooleanOptionSet(kvs, key, defaultValueIfKeyAbsent, true);\n    }\n\n    static boolean isBooleanOptionSet(\n            @Nullable final Map<String, String> kvs, @NonNull String key,\n            boolean defaultValueIfKeyAbsent, boolean defaultValueIfValueAbsent\n    ) {\n        final String value;\n\n        final Properties properties = System.getProperties();\n        if (properties.containsKey(key)) {\n            value = properties.getProperty(key).trim();\n        } else {\n            if (kvs == null) return defaultValueIfKeyAbsent;\n\n            final boolean containsKey = kvs.containsKey(key);\n            if (!containsKey) return defaultValueIfKeyAbsent;\n\n            value = kvs.get(key).trim();\n        }\n\n        // if value is blank\n        if (value.isEmpty()) return defaultValueIfValueAbsent;\n\n        return !\"false\".equalsIgnoreCase(value);\n    }\n\n    @NonNull\n    static String getStringOptionValue(\n            @Nullable final Map<String, String> kvs, @NonNull String key,\n            @NonNull String defaultValue\n    ) {\n        final String value;\n\n        final Properties properties = System.getProperties();\n        if (properties.containsKey(key)) {\n            value = properties.getProperty(key).trim();\n        } else {\n            if (kvs == null) return defaultValue;\n\n            final boolean containsKey = kvs.containsKey(key);\n            if (!containsKey) return defaultValue;\n\n            value = kvs.get(key).trim();\n        }\n\n        // if value is blank\n        if (value.isEmpty()) return defaultValue;\n\n        return value;\n    }\n\n    @NonNull\n    @SuppressWarnings(\"unchecked\")\n    static List<String> getOptionStringListValues(@Nullable final Map<String, String> kvs, @NonNull String key) {\n        final String value;\n\n        final Properties properties = System.getProperties();\n        if (properties.containsKey(key)) {\n            value = properties.getProperty(key);\n        } else {\n            if (kvs == null) return Collections.EMPTY_LIST;\n\n            value = kvs.get(key);\n        }\n\n        return splitListStringToStringList(value);\n    }\n\n    // ======== Simple Parse Util Methods ========\n\n    /**\n     * Split {@code json} like String({@code \"k1:v1,k2:v2\"}) to KV map({@code \"k1\"->\"v1\", \"k2\"->\"v2\"}).\n     */\n    @NonNull\n    static Map<String, String> splitCommaColonStringToKV(@Nullable final String commaColonString) {\n        final Map<String, String> ret = new HashMap<>();\n        if (commaColonString == null || commaColonString.trim().length() == 0) return ret;\n\n        final String[] splitKvArray = commaColonString.trim().split(\"\\\\s*,\\\\s*\");\n        for (String kvString : splitKvArray) {\n            final String[] kv = kvString.trim().split(\"\\\\s*:\\\\s*\");\n            if (kv.length == 0) continue;\n\n            if (kv.length == 1) ret.put(kv[0], \"\");\n            else ret.put(kv[0], kv[1]);\n        }\n\n        return ret;\n    }\n\n    /**\n     * Split String {@code \"v1|v2|v3\"} to String List({@code [v1, v2, v3]}).\n     */\n    @NonNull\n    static List<String> splitListStringToStringList(@Nullable String listString) {\n        final List<String> ret = new ArrayList<>();\n        if (listString == null || listString.trim().length() == 0) return ret;\n\n        final String[] split = listString.trim().split(\"\\\\s*\\\\|\\\\s*\");\n        for (String s : split) {\n            if (s.length() == 0) continue;\n\n            ret.add(s);\n        }\n\n        return ret;\n    }\n\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlAgentHelper() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/TtlExtensionTransformletManager.java",
    "content": "package com.alibaba.ttl3.agent;\n\nimport com.alibaba.ttl3.agent.logging.Logger;\nimport com.alibaba.ttl3.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl3.agent.transformlet.TtlTransformlet;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport javassist.CannotCompileException;\nimport javassist.NotFoundException;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.lang.reflect.InvocationTargetException;\nimport java.net.URL;\nimport java.util.*;\n\nimport static com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper.getLocationUrlOfClass;\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfinal class TtlExtensionTransformletManager {\n    private static final Logger logger = Logger.getLogger(TtlExtensionTransformletManager.class);\n\n    private static final String TTL_AGENT_EXTENSION_TRANSFORMLET_FILE = \"META-INF/ttl.agent.transformlets\";\n\n    public TtlExtensionTransformletManager() {\n    }\n\n    public String extensionTransformletDoTransform(@NonNull final ClassInfo classInfo) throws NotFoundException, CannotCompileException, IOException {\n        final Map<String, TtlTransformlet> transformlets = classLoader2ExtensionTransformletsIncludeParentCL.get(classInfo.getClassLoader());\n        if (transformlets == null) return null;\n\n        for (Map.Entry<String, TtlTransformlet> entry : transformlets.entrySet()) {\n            final String className = entry.getKey();\n            final TtlTransformlet transformlet = entry.getValue();\n\n            transformlet.doTransform(classInfo);\n            if (classInfo.isModified()) {\n                return className;\n            }\n        }\n\n        return null;\n    }\n\n    // NOTE: use WeakHashMap as a Set collection, value is always null.\n    private final WeakHashMap<ClassLoader, ?> collectedClassLoaderHistory = new WeakHashMap<>(512);\n\n    // Map: ExtensionTransformlet ClassLoader -> ExtensionTransformlet ClassName -> ExtensionTransformlet instance(not include from parent classloader)\n    private final WeakHashMap<ClassLoader, Map<String, TtlTransformlet>> classLoader2ExtensionTransformlets =\n            new WeakHashMap<>(512);\n\n    // Map: ExtensionTransformlet ClassLoader -> ExtensionTransformlet ClassName -> ExtensionTransformlet instance(include from parent classloader)\n    private final WeakHashMap<ClassLoader, Map<String, TtlTransformlet>> classLoader2ExtensionTransformletsIncludeParentCL =\n            new WeakHashMap<>(512);\n\n    public void collectExtensionTransformlet(@NonNull final ClassInfo classInfo) throws IOException {\n        final ClassLoader classLoader = classInfo.getClassLoader();\n        // classloader may null be if the bootstrap loader,\n        // which classloader must contains NO Ttl Agent Extension Transformlet, so just safe skip\n        if (classLoader == null) return;\n\n        // this classLoader is collected, so skip collection\n        if (collectedClassLoaderHistory.containsKey(classLoader)) return;\n        collectedClassLoaderHistory.put(classLoader, null);\n\n        logger.info(\"[TtlExtensionTransformletCollector] collecting TTL Extension Transformlets from classloader \" + classLoader);\n\n        final LinkedHashSet<String> extensionTransformletClassNames = readExtensionTransformletClassNames(classLoader);\n\n        final String foundMsgHead = \"[TtlExtensionTransformletCollector] found TTL Extension Transformlet class \";\n        final String failLoadMsgHead = \"[TtlExtensionTransformletCollector] fail to load TTL Extension Transformlet \";\n        final Map<ClassLoader, Set<TtlTransformlet>> loadedTransformlet =\n                loadExtensionInstances(classLoader, extensionTransformletClassNames, TtlTransformlet.class, foundMsgHead, failLoadMsgHead);\n\n        mergeToClassLoader2ExtensionTransformlet(classLoader2ExtensionTransformlets, loadedTransformlet);\n\n        updateClassLoader2ExtensionTransformletsIncludeParentCL(\n                classLoader2ExtensionTransformlets, classLoader2ExtensionTransformletsIncludeParentCL);\n    }\n\n    // extension transformlet configuration file URL location string -> URL contained extension transformlet class names\n    private final Map<String, LinkedHashSet<String>> redExtensionTransformletFileHistory = new HashMap<>();\n\n    private LinkedHashSet<String> readExtensionTransformletClassNames(ClassLoader classLoader) throws IOException {\n        final Enumeration<URL> extensionFiles = classLoader.getResources(TTL_AGENT_EXTENSION_TRANSFORMLET_FILE);\n\n        final Pair<LinkedHashSet<String>, Set<String>> pair = readLinesFromExtensionFiles(extensionFiles, redExtensionTransformletFileHistory);\n        final LinkedHashSet<String> extensionTransformletClassNames = pair.first;\n        final Set<String> stringUrls = pair.second;\n        if (!stringUrls.isEmpty())\n            logger.info(\"[TtlExtensionTransformletCollector] found TTL Extension Transformlet configuration files from classloader \"\n                    + classLoader + \" : \" + stringUrls);\n\n        return extensionTransformletClassNames;\n    }\n\n    private static void mergeToClassLoader2ExtensionTransformlet(\n            Map<ClassLoader, Map<String, TtlTransformlet>> destination, Map<ClassLoader, Set<TtlTransformlet>> loadedTransformlets\n    ) {\n        for (Map.Entry<ClassLoader, Set<TtlTransformlet>> entry : loadedTransformlets.entrySet()) {\n            final ClassLoader classLoader = entry.getKey();\n            final Set<TtlTransformlet> transformlets = entry.getValue();\n\n            Map<String, TtlTransformlet> className2Transformlets = destination.computeIfAbsent(classLoader, k -> new HashMap<>());\n\n            for (TtlTransformlet t : transformlets) {\n                final String className = t.getClass().getName();\n                if (className2Transformlets.containsKey(className)) continue;\n\n                className2Transformlets.put(className, t);\n                logger.info(\"[TtlExtensionTransformletCollector] add TTL Extension Transformlet \" + className + \" success\");\n            }\n        }\n    }\n\n    static void updateClassLoader2ExtensionTransformletsIncludeParentCL(\n            Map<ClassLoader, Map<String, TtlTransformlet>> classLoader2ExtensionTransformlets,\n            Map<ClassLoader, Map<String, TtlTransformlet>> classLoader2ExtensionTransformletsIncludeParentCL\n    ) {\n        for (Map.Entry<ClassLoader, Map<String, TtlTransformlet>> entry : classLoader2ExtensionTransformlets.entrySet()) {\n            final ClassLoader classLoader = entry.getKey();\n            final Map<String, TtlTransformlet> merged = childClassLoaderFirstMergeTransformlets(classLoader2ExtensionTransformlets, classLoader);\n            classLoader2ExtensionTransformletsIncludeParentCL.put(classLoader, merged);\n        }\n    }\n\n    static Map<String, TtlTransformlet> childClassLoaderFirstMergeTransformlets(\n            Map<ClassLoader, Map<String, TtlTransformlet>> classLoader2Transformlet, ClassLoader classLoader\n    ) {\n        Map<String, TtlTransformlet> ret = new HashMap<>();\n\n        final ArrayDeque<ClassLoader> chain = new ArrayDeque<>();\n        chain.add(classLoader);\n        while (classLoader.getParent() != null) {\n            classLoader = classLoader.getParent();\n\n            chain.addFirst(classLoader);\n        }\n\n        for (ClassLoader loader : chain) {\n            final Map<String, TtlTransformlet> m = classLoader2Transformlet.get(loader);\n            if (m == null) continue;\n\n            ret.putAll(m);\n        }\n\n        return ret;\n    }\n\n    // ======== Extension load util methods ========\n\n    static <T> Map<ClassLoader, Set<T>> loadExtensionInstances(\n            ClassLoader classLoader, LinkedHashSet<String> instanceClassNames, Class<T> superType,\n            String foundMsgHead, String failLoadMsgHead\n    ) {\n        Map<ClassLoader, Set<T>> ret = new HashMap<>();\n\n        for (final String className : instanceClassNames) {\n            try {\n                final Class<?> clazz = classLoader.loadClass(className);\n                if (!superType.isAssignableFrom(clazz)) {\n                    final String msg = foundMsgHead + className\n                            + \" from classloader \" + classLoader\n                            + \" at location \" + getLocationUrlOfClass(clazz)\n                            + \", but NOT subtype of \" + superType.getName() + \", ignored!\";\n                    logger.error(msg);\n                    continue;\n                }\n\n                Object instance = clazz.getDeclaredConstructor().newInstance();\n\n                final ClassLoader actualClassLoader = instance.getClass().getClassLoader();\n                Set<T> set = ret.computeIfAbsent(actualClassLoader, k -> new HashSet<>());\n                set.add(superType.cast(instance));\n\n                final String msg = foundMsgHead + className\n                        + \", and loaded from classloader \" + classLoader\n                        + \" at location \" + getLocationUrlOfClass(clazz);\n                logger.info(msg);\n            } catch (ClassNotFoundException e) {\n                final String msg = failLoadMsgHead + className + \" from classloader \" + classLoader + \", cause: \" + e.toString();\n                logger.warn(msg, e);\n            } catch (IllegalAccessException | InstantiationException | NoSuchMethodException |\n                     InvocationTargetException e) {\n                final String msg = failLoadMsgHead + className + \" from classloader \" + classLoader + \", cause: \" + e.toString();\n                logger.error(msg, e);\n            }\n        }\n\n        return ret;\n    }\n\n    // return: read lines from URL, url strings\n    @NonNull\n    static Pair<LinkedHashSet<String>, Set<String>> readLinesFromExtensionFiles(\n            /* input */ @NonNull Enumeration<URL> extensionFiles,\n            /* input/output, map url string -> content lines */ @NonNull Map<String, LinkedHashSet<String>> redExtensionFilesHistory\n    ) {\n        final LinkedHashSet<String> mergedLines = new LinkedHashSet<>();\n        final Set<String> stringUrls = new HashSet<>();\n\n        while (extensionFiles.hasMoreElements()) {\n            final URL url = extensionFiles.nextElement();\n\n            final String urlString = url.toString();\n            stringUrls.add(urlString);\n\n            LinkedHashSet<String> lines;\n            if (redExtensionFilesHistory.containsKey(urlString)) {\n                lines = redExtensionFilesHistory.get(urlString);\n            } else {\n                lines = readLines(url);\n\n                redExtensionFilesHistory.put(urlString, lines);\n            }\n\n            mergedLines.addAll(lines);\n        }\n\n        return new Pair<>(mergedLines, stringUrls);\n    }\n\n    /**\n     * this method is modified based on {@link ServiceLoader}\n     */\n    @SuppressWarnings(\"StatementWithEmptyBody\")\n    static LinkedHashSet<String> readLines(URL extensionFile) {\n        InputStream inputStream = null;\n        BufferedReader reader = null;\n\n        LinkedHashSet<String> names = new LinkedHashSet<>();\n        try {\n            inputStream = extensionFile.openStream();\n            reader = new BufferedReader(new InputStreamReader(inputStream, UTF_8));\n            int lineNum = 1;\n            while ((lineNum = parseLine(extensionFile, reader, lineNum, names)) >= 0) ;\n        } catch (IOException x) {\n            logger.error(\"Error reading configuration file \" + extensionFile, x);\n        } finally {\n            try {\n                if (reader != null) reader.close();\n                if (inputStream != null) inputStream.close();\n            } catch (IOException y) {\n                logger.warn(\"Error closing configuration file \" + extensionFile, y);\n            }\n        }\n\n        return names;\n    }\n\n\n    /**\n     * this method is modified based on {@link ServiceLoader}\n     */\n    private static int parseLine(URL url, BufferedReader reader, int lineNum, LinkedHashSet<String> names) throws IOException {\n        String line = reader.readLine();\n        if (line == null) {\n            return -1;\n        }\n\n        // remove comments that start with `#`\n        int ci = line.indexOf('#');\n        if (ci >= 0) line = line.substring(0, ci);\n\n        line = line.trim();\n\n        int n = line.length();\n        if (n != 0) {\n            if ((line.indexOf(' ') >= 0) || (line.indexOf('\\t') >= 0)) {\n                logger.error(\"Illegal syntax \" + line + \"in configuration file\" + url + \", contains space or tab; ignore this line!\");\n                return lineNum + 1;\n            }\n\n            int cp = line.codePointAt(0);\n            if (!Character.isJavaIdentifierStart(cp)) {\n                logger.error(\"Illegal extension class name \" + line + \" in configuration file \" + url + \"; ignore this line!\");\n                return lineNum + 1;\n            }\n            for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {\n                cp = line.codePointAt(i);\n                if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {\n                    logger.error(\"Illegal extension class name: \" + line + \" in configuration file \" + url + \"; ignore this line!\");\n                    return lineNum + 1;\n                }\n            }\n\n            names.add(line);\n        }\n\n        return lineNum + 1;\n    }\n\n    static class Pair<T, U> {\n        T first;\n        U second;\n\n        public Pair(T first, U second) {\n            this.first = first;\n            this.second = second;\n        }\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/TtlTransformer.java",
    "content": "package com.alibaba.ttl3.agent;\n\nimport com.alibaba.ttl3.agent.logging.Logger;\nimport com.alibaba.ttl3.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl3.agent.transformlet.TtlTransformlet;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.lang.instrument.ClassFileTransformer;\nimport java.security.ProtectionDomain;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper.isClassUnderPackage;\n\n/**\n * TTL {@link ClassFileTransformer} of Java Agent\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see ClassFileTransformer\n * @see <a href=\"https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html\">The mechanism for instrumentation</a>\n */\npublic class TtlTransformer implements ClassFileTransformer {\n    private static final Logger logger = Logger.getLogger(TtlTransformer.class);\n\n    /**\n     * \"<code>null</code> if no transform is performed\",\n     * see {@code @return} of {@link ClassFileTransformer#transform(ClassLoader, String, Class, ProtectionDomain, byte[])}\n     */\n    @SuppressFBWarnings({\"EI_EXPOSE_REP\"})\n    // [ERROR] com.alibaba.ttl3.agent.TtlTransformer.transform(ClassLoader, String, Class, ProtectionDomain, byte[])\n    //         may expose internal representation by returning TtlTransformer.NO_TRANSFORM\n    // the value is null, so there is NO \"EI_EXPOSE_REP\" problem actually.\n    private static final byte[] NO_TRANSFORM = null;\n\n    private final TtlExtensionTransformletManager extensionTransformletManager;\n    private final List<TtlTransformlet> transformletList = new ArrayList<>();\n    private final boolean logClassTransform;\n\n    TtlTransformer(List<? extends TtlTransformlet> transformletList, boolean logClassTransform) {\n        extensionTransformletManager = new TtlExtensionTransformletManager();\n\n        this.logClassTransform = logClassTransform;\n        for (TtlTransformlet ttlTransformlet : transformletList) {\n            this.transformletList.add(ttlTransformlet);\n            logger.info(\"[TtlTransformer] add Transformlet \" + ttlTransformlet.getClass().getName());\n        }\n    }\n\n    /**\n     * info about class loader: may be <code>null</code> if the bootstrap loader.\n     * <p>\n     * more info see {@link ClassFileTransformer#transform(ClassLoader, String, Class, ProtectionDomain, byte[])}\n     */\n    @Override\n    public final byte[] transform(@Nullable final ClassLoader loader, @Nullable final String classFile, final Class<?> classBeingRedefined,\n                                  final ProtectionDomain protectionDomain, @NonNull final byte[] classFileBuffer) {\n        try {\n            // Lambda has no class file, no need to transform, just return.\n            if (classFile == null) return NO_TRANSFORM;\n\n            final ClassInfo classInfo = new ClassInfo(classFile, classFileBuffer, loader);\n            if (isClassUnderPackage(classInfo.getClassName(), \"com.alibaba.ttl\")) return NO_TRANSFORM;\n            if (isClassUnderPackage(classInfo.getClassName(), \"java.lang\")) return NO_TRANSFORM;\n\n            if (logClassTransform)\n                logger.info(\"[TtlTransformer] transforming \" + classInfo.getClassName()\n                        + \" from classloader \" + classInfo.getClassLoader()\n                        + \" at location \" + classInfo.getLocationUrl());\n\n            extensionTransformletManager.collectExtensionTransformlet(classInfo);\n\n            for (TtlTransformlet transformlet : transformletList) {\n                transformlet.doTransform(classInfo);\n                if (classInfo.isModified()) {\n                    logger.info(\"[TtlTransformer] \" + transformlet.getClass().getName() + \" transformed \" + classInfo.getClassName()\n                            + \" from classloader \" + classInfo.getClassLoader()\n                            + \" at location \" + classInfo.getLocationUrl());\n                    return classInfo.getCtClass().toBytecode();\n                }\n            }\n\n            final String transformlet = extensionTransformletManager.extensionTransformletDoTransform(classInfo);\n            if (classInfo.isModified()) {\n                logger.info(\"[TtlTransformer] \" + transformlet + \" transformed \" + classInfo.getClassName()\n                        + \" from classloader \" + classInfo.getClassLoader()\n                        + \" at location \" + classInfo.getLocationUrl());\n                return classInfo.getCtClass().toBytecode();\n            }\n        } catch (Throwable t) {\n            String msg = \"[TtlTransformer] fail to transform class \" + classFile + \", cause: \" + t.toString();\n            logger.error(msg, t);\n            throw new IllegalStateException(msg, t);\n        }\n\n        return NO_TRANSFORM;\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/logging/Logger.java",
    "content": "package com.alibaba.ttl3.agent.logging;\n\nimport com.alibaba.ttl3.agent.TtlAgent;\nimport com.alibaba.ttl3.agent.transformlet.TtlTransformlet;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.logging.Level;\n\n/**\n * Logger adaptor for ttl TTL agent/transformlet. Only use for TTL agent/transformlet!\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see TtlTransformlet\n * @see TtlAgent\n */\npublic abstract class Logger {\n    public static final String STDOUT = \"STDOUT\";\n    public static final String STDERR = \"STDERR\";\n\n    private static volatile int loggerImplType = -1;\n\n    public static void setLoggerImplType(String type) {\n        if (loggerImplType != -1) {\n            throw new IllegalStateException(\"TTL logger implementation type is already set! type = \" + loggerImplType);\n        }\n\n        if (STDERR.equalsIgnoreCase(type)) loggerImplType = 0;\n        else if (STDOUT.equalsIgnoreCase(type)) loggerImplType = 1;\n        else loggerImplType = 0;\n    }\n\n    /**\n     * Only for test code\n     */\n    public static void setLoggerImplTypeIfNotSetYet(String type) {\n        if (loggerImplType == -1) setLoggerImplType(type);\n    }\n\n    public static Logger getLogger(Class<?> clazz) {\n        if (loggerImplType == -1) throw new IllegalStateException(\"TTL logger implementation type is NOT set!\");\n\n        switch (loggerImplType) {\n            case 1:\n                return new StdOutLogger(clazz);\n            default:\n                return new StdErrorLogger(clazz);\n        }\n    }\n\n    final Class<?> logClass;\n\n    private Logger(Class<?> logClass) {\n        this.logClass = logClass;\n    }\n\n    public void info(String msg) {\n        log(Level.INFO, msg, null);\n    }\n\n    public void warn(String msg) {\n        log(Level.WARNING, msg, null);\n    }\n\n    public void warn(String msg, Throwable thrown) {\n        log(Level.WARNING, msg, thrown);\n    }\n\n    public void error(String msg) {\n        log(Level.SEVERE, msg, null);\n    }\n\n    public void error(String msg, Throwable thrown) {\n        log(Level.SEVERE, msg, thrown);\n    }\n\n    protected abstract void log(Level level, String msg, Throwable thrown);\n\n    private static class StdErrorLogger extends Logger {\n        StdErrorLogger(Class<?> clazz) {\n            super(clazz);\n        }\n\n        @Override\n        public void log(Level level, String msg, Throwable thrown) {\n            if (level == Level.SEVERE) {\n                final String time = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\").format(new Date());\n                System.err.printf(\"%s %s [%s] %s: %s%n\", time, level, Thread.currentThread().getName(), logClass.getSimpleName(), msg);\n                if (thrown != null) thrown.printStackTrace();\n            }\n        }\n    }\n\n    private static class StdOutLogger extends Logger {\n        StdOutLogger(Class<?> clazz) {\n            super(clazz);\n        }\n\n        @Override\n        public void log(Level level, String msg, Throwable thrown) {\n            final String time = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\").format(new Date());\n            System.out.printf(\"%s %s [%s] %s: %s%n\", time, level, Thread.currentThread().getName(), logClass.getSimpleName(), msg);\n            if (thrown != null) thrown.printStackTrace(System.out);\n        }\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/logging/package-info.java",
    "content": "/**\n * TTL Agent Logger. <b>Only</b> use for TTL agent/transformlet.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.agent.logging.Logger\n */\npackage com.alibaba.ttl3.agent.logging;\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/package-info.java",
    "content": "/**\n * TTL Agent.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.agent.TtlAgent\n * @see <a href=\"https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html\">The mechanism for instrumentation</a>\n */\npackage com.alibaba.ttl3.agent;\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/ClassInfo.java",
    "content": "package com.alibaba.ttl3.agent.transformlet;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport javassist.ClassPool;\nimport javassist.CtClass;\nimport javassist.LoaderClassPath;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.net.URL;\n\nimport static com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper.getLocationUrlOfClass;\n\n/**\n * Class Info for {@link TtlTransformlet}.\n *\n * <B><I>Caution:</I></B><br>\n * Do <b>NOT</b> load {@link Class} which is transforming, or the transform will lose effectiveness.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\npublic class ClassInfo {\n    private final String transformerClassFile;\n    private final String className;\n    private final byte[] classFileBuffer;\n    private final ClassLoader loader;\n\n    // SuppressFBWarnings for classFileBuffer/loader parameter:\n    //   [ERROR] new com.alibaba.ttl3.agent.transformlet.ClassInfo(String, byte[], ClassLoader)\n    //   may expose internal representation by storing an externally mutable object\n    //   into ClassInfo.classFileBuffer/loader\n    public ClassInfo(@NonNull String transformerClassFile,\n                     @NonNull @SuppressFBWarnings({\"EI_EXPOSE_REP2\"}) byte[] classFileBuffer,\n                     @Nullable @SuppressFBWarnings({\"EI_EXPOSE_REP2\"}) ClassLoader loader) {\n        this.transformerClassFile = transformerClassFile;\n        this.className = toClassName(transformerClassFile);\n        this.classFileBuffer = classFileBuffer;\n        this.loader = loader;\n    }\n\n    @NonNull\n    public String getClassName() {\n        return className;\n    }\n\n    private CtClass ctClass;\n\n    public URL getLocationUrl() throws IOException {\n        return getLocationUrlOfClass(getCtClass());\n    }\n\n    @NonNull\n    @SuppressFBWarnings({\"EI_EXPOSE_REP\"})\n    // [ERROR] Medium: com.alibaba.ttl3.agent.transformlet.ClassInfo.getCtClass()\n    // may expose internal representation\n    // by returning ClassInfo.ctClass [com.alibaba.ttl3.agent.transformlet.ClassInfo]\n    public CtClass getCtClass() throws IOException {\n        if (ctClass != null) return ctClass;\n\n        final ClassPool classPool = new ClassPool(true);\n        if (loader == null) {\n            classPool.appendClassPath(new LoaderClassPath(ClassLoader.getSystemClassLoader()));\n        } else {\n            classPool.appendClassPath(new LoaderClassPath(loader));\n        }\n\n        final CtClass clazz = classPool.makeClass(new ByteArrayInputStream(classFileBuffer), false);\n        clazz.defrost();\n\n        this.ctClass = clazz;\n        return clazz;\n    }\n\n    private boolean modified = false;\n\n    public boolean isModified() {\n        return modified;\n    }\n\n    public void setModified() {\n        this.modified = true;\n    }\n\n    @SuppressFBWarnings({\"EI_EXPOSE_REP\"})\n    // [ERROR] Medium: com.alibaba.ttl3.agent.transformlet.ClassInfo.getClassLoader()\n    // may expose internal representation\n    // by returning ClassInfo.loader [com.alibaba.ttl3.agent.transformlet.ClassInfo]\n    public ClassLoader getClassLoader() {\n        return loader;\n    }\n\n    private static String toClassName(@NonNull final String classFile) {\n        return classFile.replace('/', '.');\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/TtlTransformlet.java",
    "content": "package com.alibaba.ttl3.agent.transformlet;\n\nimport com.alibaba.ttl3.agent.TtlTransformer;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport javassist.CannotCompileException;\nimport javassist.NotFoundException;\n\nimport java.io.IOException;\n\n/**\n * TTL {@code Transformlet}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\npublic interface TtlTransformlet {\n    /**\n     * info about class loader: may be <code>null</code> if the bootstrap loader.\n     * <p>\n     * more info see {@link java.lang.instrument.ClassFileTransformer#transform(ClassLoader, String, Class, java.security.ProtectionDomain, byte[])}\n     *\n     * @see TtlTransformer#transform(ClassLoader, String, Class, java.security.ProtectionDomain, byte[])\n     * @see java.lang.instrument.ClassFileTransformer#transform\n     */\n    void doTransform(@NonNull ClassInfo classInfo) throws CannotCompileException, NotFoundException, IOException;\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/helper/AbstractExecutorTtlTransformlet.java",
    "content": "package com.alibaba.ttl3.agent.transformlet.helper;\n\nimport com.alibaba.ttl3.agent.logging.Logger;\nimport com.alibaba.ttl3.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl3.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl3.agent.transformlet.internal.PriorityBlockingQueueTtlTransformlet;\nimport com.alibaba.ttl3.spi.TtlAttachmentsDelegate;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport javassist.*;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\n\nimport static com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper.isClassAtPackageJavaUtil;\nimport static com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper.signatureOfMethod;\n\n/**\n * Abstract {@link TtlTransformlet} for {@link java.util.concurrent.Executor} and its subclass.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author wuwen5 (wuwen.55 at aliyun dot com)\n * @see java.util.concurrent.Executor\n * @see java.util.concurrent.ExecutorService\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ScheduledThreadPoolExecutor\n * @see java.util.concurrent.Executors\n * @see PriorityBlockingQueueTtlTransformlet\n */\npublic abstract class AbstractExecutorTtlTransformlet implements TtlTransformlet {\n    protected static final String RUNNABLE_CLASS_NAME = \"java.lang.Runnable\";\n    protected static final String CALLABLE_CLASS_NAME = \"java.util.concurrent.Callable\";\n\n    protected static final String TTL_RUNNABLE_CLASS_NAME = \"com.alibaba.ttl3.TtlRunnable\";\n    protected static final String TTL_CALLABLE_CLASS_NAME = \"com.alibaba.ttl3.TtlCallable\";\n\n    protected static final String THREAD_FACTORY_CLASS_NAME = \"java.util.concurrent.ThreadFactory\";\n    protected static final String THREAD_POOL_EXECUTOR_CLASS_NAME = \"java.util.concurrent.ThreadPoolExecutor\";\n\n    protected final Logger logger = Logger.getLogger(getClass());\n\n    protected final Set<String> executorClassNames;\n    protected final boolean disableInheritableForThreadPool;\n\n    private final Map<String, String> paramTypeNameToDecorateMethodClass = new HashMap<>();\n\n    /**\n     * @param executorClassNames the executor class names to be transformed\n     */\n    public AbstractExecutorTtlTransformlet(Set<String> executorClassNames, boolean disableInheritableForThreadPool) {\n        this.executorClassNames = Collections.unmodifiableSet(executorClassNames);\n        this.disableInheritableForThreadPool = disableInheritableForThreadPool;\n\n        paramTypeNameToDecorateMethodClass.put(RUNNABLE_CLASS_NAME, TTL_RUNNABLE_CLASS_NAME);\n        paramTypeNameToDecorateMethodClass.put(CALLABLE_CLASS_NAME, TTL_CALLABLE_CLASS_NAME);\n    }\n\n    @Override\n    public final void doTransform(@NonNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException {\n        // work-around ClassCircularityError:\n        //      https://github.com/alibaba/transmittable-thread-local/issues/278\n        //      https://github.com/alibaba/transmittable-thread-local/issues/234\n        if (isClassAtPackageJavaUtil(classInfo.getClassName())) return;\n\n        final CtClass clazz = classInfo.getCtClass();\n        if (executorClassNames.contains(classInfo.getClassName())) {\n            for (CtMethod method : clazz.getDeclaredMethods()) {\n                updateSubmitMethodsOfExecutorClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(method);\n            }\n\n            if (disableInheritableForThreadPool) updateConstructorDisableInheritable(clazz);\n\n            classInfo.setModified();\n        } else {\n            if (clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() || clazz.isAnnotation()) {\n                return;\n            }\n            if (!clazz.subclassOf(clazz.getClassPool().get(THREAD_POOL_EXECUTOR_CLASS_NAME))) return;\n\n            logger.info(\"Transforming class \" + classInfo.getClassName());\n\n            final boolean modified = updateBeforeAndAfterExecuteMethodOfExecutorSubclass(clazz);\n            if (modified) classInfo.setModified();\n        }\n    }\n\n    /**\n     * @see TtlTransformletHelper#doAutoWrap(Runnable)\n     * @see TtlTransformletHelper#doAutoWrap(Callable)\n     */\n    @SuppressFBWarnings(\"VA_FORMAT_STRING_USES_NEWLINE\") // [ERROR] Format string should use %n rather than \\n\n    private void updateSubmitMethodsOfExecutorClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(@NonNull final CtMethod method) throws NotFoundException, CannotCompileException {\n        final int modifiers = method.getModifiers();\n        if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers)) return;\n\n        CtClass[] parameterTypes = method.getParameterTypes();\n        StringBuilder insertCode = new StringBuilder();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            final String paramTypeName = parameterTypes[i].getName();\n            if (paramTypeNameToDecorateMethodClass.containsKey(paramTypeName)) {\n                String code = String.format(\n                        // auto decorate to TTL wrapper\n                        \"$%d = helper.transformlet.com.alibaba.ttl3.agent.TtlTransformletHelper.doAutoWrap($%<d);\",\n                        i + 1);\n                logger.info(\"insert code before method \" + signatureOfMethod(method) + \" of class \" + method.getDeclaringClass().getName() + \":\\n\" + code);\n                insertCode.append(code);\n            }\n        }\n        if (insertCode.length() > 0) {\n            logger.info(\"insert code before method \" + signatureOfMethod(method) + \" of class \" +\n                    method.getDeclaringClass().getName() + \":\\n\" + insertCode);\n            method.insertBefore(insertCode.toString());\n        }\n    }\n\n    /**\n     * @see com.alibaba.ttl3.executor.TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)\n     */\n    private void updateConstructorDisableInheritable(@NonNull final CtClass clazz) throws NotFoundException, CannotCompileException {\n        for (CtConstructor constructor : clazz.getDeclaredConstructors()) {\n            final CtClass[] parameterTypes = constructor.getParameterTypes();\n            final StringBuilder insertCode = new StringBuilder();\n            for (int i = 0; i < parameterTypes.length; i++) {\n                final String paramTypeName = parameterTypes[i].getName();\n                if (THREAD_FACTORY_CLASS_NAME.equals(paramTypeName)) {\n                    String code = String.format(\"$%d = com.alibaba.ttl3.executor.TtlExecutors.getDisableInheritableThreadFactory($%<d);\", i + 1);\n                    insertCode.append(code);\n                }\n            }\n            if (insertCode.length() > 0) {\n                logger.info(\"insert code before constructor \" + signatureOfMethod(constructor) + \" of class \" +\n                        constructor.getDeclaringClass().getName() + \": \" + insertCode);\n                constructor.insertBefore(insertCode.toString());\n            }\n        }\n    }\n\n    /**\n     * @see TtlAttachmentsDelegate#unwrapIfIsAutoWrapper(Object)\n     */\n    private boolean updateBeforeAndAfterExecuteMethodOfExecutorSubclass(@NonNull final CtClass clazz) throws NotFoundException, CannotCompileException {\n        final CtClass runnableClass = clazz.getClassPool().get(RUNNABLE_CLASS_NAME);\n        final CtClass threadClass = clazz.getClassPool().get(\"java.lang.Thread\");\n        final CtClass throwableClass = clazz.getClassPool().get(\"java.lang.Throwable\");\n        boolean modified = false;\n\n        try {\n            final CtMethod beforeExecute = clazz.getDeclaredMethod(\"beforeExecute\", new CtClass[]{threadClass, runnableClass});\n            // unwrap runnable if IsAutoWrapper\n            String code = \"$2 = com.alibaba.ttl3.spi.TtlAttachmentsDelegate.unwrapIfIsAutoWrapper($2);\";\n            logger.info(\"insert code before method \" + signatureOfMethod(beforeExecute) + \" of class \" +\n                    beforeExecute.getDeclaringClass().getName() + \": \" + code);\n            beforeExecute.insertBefore(code);\n            modified = true;\n        } catch (NotFoundException e) {\n            // clazz does not override beforeExecute method, do nothing.\n        }\n\n        try {\n            final CtMethod afterExecute = clazz.getDeclaredMethod(\"afterExecute\", new CtClass[]{runnableClass, throwableClass});\n            // unwrap runnable if IsAutoWrapper\n            String code = \"$1 = com.alibaba.ttl3.spi.TtlAttachmentsDelegate.unwrapIfIsAutoWrapper($1);\";\n            logger.info(\"insert code before method \" + signatureOfMethod(afterExecute) + \" of class \" +\n                    afterExecute.getDeclaringClass().getName() + \": \" + code);\n            afterExecute.insertBefore(code);\n            modified = true;\n        } catch (NotFoundException e) {\n            // clazz does not override afterExecute method, do nothing.\n        }\n\n        return modified;\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/helper/TtlTransformletHelper.java",
    "content": "package com.alibaba.ttl3.agent.transformlet.helper;\n\nimport com.alibaba.ttl3.TtlCallable;\nimport com.alibaba.ttl3.TtlRunnable;\nimport com.alibaba.ttl3.agent.logging.Logger;\nimport com.alibaba.ttl3.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport javassist.*;\n\nimport java.lang.reflect.Modifier;\nimport java.net.URL;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.concurrent.Callable;\n\nimport static com.alibaba.ttl3.spi.TtlAttachmentsDelegate.setAutoWrapperAttachment;\nimport static com.alibaba.ttl3.transmitter.Transmitter.capture;\n\n/**\n * Helper methods for {@link TtlTransformlet} implementation.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\npublic final class TtlTransformletHelper {\n    private static final Logger logger = Logger.getLogger(TtlTransformletHelper.class);\n\n    // ======== Javassist/Class Helper ========\n\n    /**\n     * Output string like {@code public ScheduledFuture scheduleAtFixedRate(Runnable, long, long, TimeUnit)}\n     * for {@link  java.util.concurrent.ScheduledThreadPoolExecutor#scheduleAtFixedRate}.\n     *\n     * @param method method object\n     * @return method signature string\n     */\n    @NonNull\n    public static String signatureOfMethod(@NonNull final CtBehavior method) throws NotFoundException {\n        final StringBuilder stringBuilder = new StringBuilder();\n\n        stringBuilder.append(Modifier.toString(method.getModifiers()));\n        if (method instanceof CtMethod) {\n            final String returnType = ((CtMethod) method).getReturnType().getSimpleName();\n            stringBuilder.append(\" \").append(returnType);\n        }\n        stringBuilder.append(\" \").append(method.getName()).append(\"(\");\n\n        final CtClass[] parameterTypes = method.getParameterTypes();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            CtClass parameterType = parameterTypes[i];\n            if (i != 0) stringBuilder.append(\", \");\n            stringBuilder.append(parameterType.getSimpleName());\n        }\n\n        stringBuilder.append(\")\");\n        return stringBuilder.toString();\n    }\n\n    public static URL getLocationUrlOfClass(CtClass clazz) {\n        try {\n            // proxy classes is dynamic, no class file\n            if (clazz.getName().startsWith(\"com.sun.proxy.\")) return null;\n\n            return clazz.getURL();\n        } catch (Exception e) {\n            logger.warn(\"Fail to getLocationUrlOfClass \" + clazz.getName() + \", cause: \" + e.toString());\n            return null;\n        }\n    }\n\n    public static String getLocationFileOfClass(CtClass clazz) {\n        final URL location = getLocationUrlOfClass(clazz);\n        if (location == null) return null;\n\n        return location.getFile();\n    }\n\n    public static URL getLocationUrlOfClass(Class<?> clazz) {\n        try {\n            // proxy classes is dynamic, no class file\n            if (clazz.getName().startsWith(\"com.sun.proxy.\")) return null;\n\n            final ProtectionDomain protectionDomain = clazz.getProtectionDomain();\n            if (protectionDomain == null) return null;\n\n            final CodeSource codeSource = protectionDomain.getCodeSource();\n            if (codeSource == null) return null;\n\n            return codeSource.getLocation();\n        } catch (Exception e) {\n            logger.warn(\"Fail to getLocationUrlOfClass \" + clazz.getName() + \", cause: \" + e.toString());\n            return null;\n        }\n    }\n\n    public static String getLocationFileOfClass(Class<?> clazz) {\n        final URL location = getLocationUrlOfClass(clazz);\n        if (location == null) return null;\n\n        return location.getFile();\n    }\n\n    // ======== Method Transform Helper ========\n\n    @NonNull\n    public static String renamedMethodNameByTtl(@NonNull CtMethod method) {\n        return \"original$\" + method.getName() + \"$method$renamed$by$ttl\";\n    }\n\n    public static String addTryFinallyToMethod(@NonNull CtMethod method, @NonNull String beforeCode, @NonNull String finallyCode) throws CannotCompileException, NotFoundException {\n        return addTryFinallyToMethod(method, renamedMethodNameByTtl(method), beforeCode, finallyCode);\n    }\n\n    /**\n     * Add {@code try-finally} logic to method.\n     *\n     * @return the body code of method rewritten\n     */\n    public static String addTryFinallyToMethod(@NonNull CtMethod method, @NonNull String nameForOriginalMethod, @NonNull String beforeCode, @NonNull String finallyCode) throws CannotCompileException, NotFoundException {\n        final CtClass clazz = method.getDeclaringClass();\n\n        final CtMethod newMethod = CtNewMethod.copy(method, clazz, null);\n        // rename original method, and set to private method(avoid reflect out renamed method unexpectedly)\n        newMethod.setName(nameForOriginalMethod);\n        newMethod.setModifiers(newMethod.getModifiers()\n                & ~Modifier.PUBLIC /* remove public */\n                & ~Modifier.PROTECTED /* remove protected */\n                | Modifier.PRIVATE /* add private */);\n        clazz.addMethod(newMethod);\n\n        final String returnOp;\n        if (method.getReturnType() == CtClass.voidType) {\n            returnOp = \"\";\n        } else {\n            returnOp = \"return \";\n        }\n        // set new method implementation\n        final String code = \"{\\n\" +\n                beforeCode + \"\\n\" +\n                \"try {\\n\" +\n                \"    \" + returnOp + nameForOriginalMethod + \"($$);\\n\" +\n                \"} finally {\\n\" +\n                \"    \" + finallyCode + \"\\n\" +\n                \"} }\";\n        method.setBody(code);\n\n        return code;\n    }\n\n    // ======== CRR Helper ========\n\n    @Nullable\n    public static Object doCaptureIfNotTtlEnhanced(@Nullable Object obj) {\n        if (obj instanceof TtlEnhanced) return null;\n        else return capture();\n    }\n\n\n    // FIXME hard-coded for type Runnable, not generic!\n    @Nullable\n    public static Runnable doAutoWrap(@Nullable final Runnable runnable) {\n        if (runnable == null) return null;\n\n        final TtlRunnable ret = TtlRunnable.get(runnable, false, true);\n\n        // have been auto wrapped?\n        if (ret != runnable) setAutoWrapperAttachment(ret);\n\n        return ret;\n    }\n\n    // FIXME hard-coded for type Callable, not generic!\n    @Nullable\n    public static <T> Callable<T> doAutoWrap(@Nullable final Callable<T> callable) {\n        if (callable == null) return null;\n\n        final TtlCallable<T> ret = TtlCallable.get(callable, false, true);\n\n        // have been auto wrapped?\n        if (ret != callable) setAutoWrapperAttachment(ret);\n\n        return ret;\n    }\n\n    // ======== class/package info Helper ========\n\n    @NonNull\n    public static String getPackageName(@NonNull String className) {\n        final int idx = className.lastIndexOf('.');\n        if (-1 == idx) return \"\";\n\n        return className.substring(0, idx);\n    }\n\n    public static boolean isClassAtPackage(@NonNull String className, @NonNull String packageName) {\n        return packageName.equals(getPackageName(className));\n    }\n\n    public static boolean isClassUnderPackage(@NonNull String className, @NonNull String packageName) {\n        String packageOfClass = getPackageName(className);\n        return packageOfClass.equals(packageName) || packageOfClass.startsWith(packageName + \".\");\n    }\n\n    public static boolean isClassAtPackageJavaUtil(@NonNull String className) {\n        return isClassAtPackage(className, \"java.util\");\n    }\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlTransformletHelper() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/helper/package-info.java",
    "content": "/**\n * Helper API for TTL Agent extension {@code Transformlet} development.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.agent.transformlet.TtlTransformlet\n */\npackage com.alibaba.ttl3.agent.transformlet.helper;\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/ForkJoinTtlTransformlet.java",
    "content": "package com.alibaba.ttl3.agent.transformlet.internal;\n\nimport com.alibaba.ttl3.agent.TtlAgent;\nimport com.alibaba.ttl3.agent.logging.Logger;\nimport com.alibaba.ttl3.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl3.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport javassist.*;\n\nimport java.io.IOException;\n\nimport static com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper.*;\n\n/**\n * {@link TtlTransformlet} for {@link java.util.concurrent.ForkJoinTask}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author wuwen5 (wuwen.55 at aliyun dot com)\n * @see java.util.concurrent.ForkJoinPool\n * @see java.util.concurrent.ForkJoinTask\n */\npublic final class ForkJoinTtlTransformlet implements TtlTransformlet {\n    private static final Logger logger = Logger.getLogger(ForkJoinTtlTransformlet.class);\n\n    private static final String FORK_JOIN_TASK_CLASS_NAME = \"java.util.concurrent.ForkJoinTask\";\n    private static final String FORK_JOIN_POOL_CLASS_NAME = \"java.util.concurrent.ForkJoinPool\";\n    private static final String FORK_JOIN_WORKER_THREAD_FACTORY_CLASS_NAME = \"java.util.concurrent.ForkJoinPool$ForkJoinWorkerThreadFactory\";\n\n    private final boolean disableInheritableForThreadPool;\n\n    public ForkJoinTtlTransformlet() {\n        this.disableInheritableForThreadPool = TtlAgent.isDisableInheritableForThreadPool();\n    }\n\n    @Override\n    public void doTransform(@NonNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException {\n        if (FORK_JOIN_TASK_CLASS_NAME.equals(classInfo.getClassName())) {\n            updateForkJoinTaskClass(classInfo.getCtClass());\n            classInfo.setModified();\n        } else if (disableInheritableForThreadPool && FORK_JOIN_POOL_CLASS_NAME.equals(classInfo.getClassName())) {\n            updateConstructorDisableInheritable(classInfo.getCtClass());\n            classInfo.setModified();\n        }\n    }\n\n    /**\n     * @see TtlTransformletHelper#doCaptureIfNotTtlEnhanced(Object)\n     */\n    private void updateForkJoinTaskClass(@NonNull final CtClass clazz) throws CannotCompileException, NotFoundException {\n        final String className = clazz.getName();\n\n        // add new field\n        final String capturedFieldName = \"captured$field$added$by$ttl\";\n        final CtField capturedField = CtField.make(\"private final Object \" + capturedFieldName + \";\", clazz);\n        clazz.addField(capturedField, \"com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper.doCaptureIfNotTtlEnhanced(this);\");\n        logger.info(\"add new field \" + capturedFieldName + \" to class \" + className);\n\n        final CtMethod doExecMethod = clazz.getDeclaredMethod(\"doExec\", new CtClass[0]);\n        final String doExec_renamed_method_name = renamedMethodNameByTtl(doExecMethod);\n\n        final String beforeCode = \"if (this instanceof \" + TtlEnhanced.class.getName() + \") {\\n\" + // if the class is already TTL enhanced(eg: com.alibaba.ttl3.TtlRecursiveTask)\n                \"    return \" + doExec_renamed_method_name + \"($$);\\n\" +                           // return directly/do nothing\n                \"}\\n\" +\n                \"Object backup = com.alibaba.ttl3.transmitter.Transmitter.replay(\" + capturedFieldName + \");\";\n\n        final String finallyCode = \"com.alibaba.ttl3.transmitter.Transmitter.restore(backup);\";\n\n        final String code = addTryFinallyToMethod(doExecMethod, doExec_renamed_method_name, beforeCode, finallyCode);\n        logger.info(\"insert code around method \" + signatureOfMethod(doExecMethod) + \" of class \" + clazz.getName() + \": \" + code);\n    }\n\n    private void updateConstructorDisableInheritable(@NonNull final CtClass clazz) throws NotFoundException, CannotCompileException {\n        for (CtConstructor constructor : clazz.getDeclaredConstructors()) {\n            final CtClass[] parameterTypes = constructor.getParameterTypes();\n            final StringBuilder insertCode = new StringBuilder();\n            for (int i = 0; i < parameterTypes.length; i++) {\n                final String paramTypeName = parameterTypes[i].getName();\n                if (FORK_JOIN_WORKER_THREAD_FACTORY_CLASS_NAME.equals(paramTypeName)) {\n                    String code = String.format(\"$%d = com.alibaba.ttl3.executor.TtlForkJoinPoolHelper.getDisableInheritableForkJoinWorkerThreadFactory($%<d);\", i + 1);\n                    insertCode.append(code);\n                }\n            }\n            if (insertCode.length() > 0) {\n                logger.info(\"insert code before method \" + signatureOfMethod(constructor) + \" of class \" +\n                        constructor.getDeclaringClass().getName() + \": \" + insertCode);\n                constructor.insertBefore(insertCode.toString());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/JdkExecutorTtlTransformlet.java",
    "content": "package com.alibaba.ttl3.agent.transformlet.internal;\n\nimport com.alibaba.ttl3.agent.TtlAgent;\nimport com.alibaba.ttl3.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl3.agent.transformlet.helper.AbstractExecutorTtlTransformlet;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * {@link TtlTransformlet} for {@link java.util.concurrent.ThreadPoolExecutor}\n * and {@link java.util.concurrent.ScheduledThreadPoolExecutor}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author wuwen5 (wuwen.55 at aliyun dot com)\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ScheduledThreadPoolExecutor\n */\npublic final class JdkExecutorTtlTransformlet extends AbstractExecutorTtlTransformlet implements TtlTransformlet {\n\n    private static Set<String> getExecutorClassNames() {\n        Set<String> executorClassNames = new HashSet<>();\n\n        executorClassNames.add(THREAD_POOL_EXECUTOR_CLASS_NAME);\n        executorClassNames.add(\"java.util.concurrent.ScheduledThreadPoolExecutor\");\n\n        return executorClassNames;\n    }\n\n    public JdkExecutorTtlTransformlet() {\n        super(getExecutorClassNames(), TtlAgent.isDisableInheritableForThreadPool());\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/PriorityBlockingQueueTtlTransformlet.java",
    "content": "package com.alibaba.ttl3.agent.transformlet.internal;\n\nimport com.alibaba.ttl3.agent.logging.Logger;\nimport com.alibaba.ttl3.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl3.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl3.executor.TtlExecutors;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport javassist.CannotCompileException;\nimport javassist.CtClass;\nimport javassist.CtConstructor;\nimport javassist.NotFoundException;\n\nimport java.io.IOException;\nimport java.util.Comparator;\n\nimport static com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper.signatureOfMethod;\n\n/**\n * TTL {@link TtlTransformlet} for {@link java.util.concurrent.PriorityBlockingQueue PriorityBlockingQueue}.\n * <p>\n * Avoid {@code ClassCastException(TtlRunnable cannot be cast to Comparable)} problem\n * for combination usage:\n * <ul>\n * <li>use {@link java.util.concurrent.PriorityBlockingQueue PriorityBlockingQueue} for {@link java.util.concurrent.ThreadPoolExecutor ThreadPoolExecutor}</li>\n * <li>use {@code TTL Agent} {@link JdkExecutorTtlTransformlet}</li>\n * </ul>\n * More info see <a href=\"https://github.com/alibaba/transmittable-thread-local/issues/330\">issue #330</a>\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see TtlExecutors#getTtlRunnableUnwrapComparator(Comparator)\n * @see TtlExecutors#getTtlRunnableUnwrapComparatorForComparableRunnable()\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue)\n * @see java.util.concurrent.PriorityBlockingQueue\n * @see java.util.concurrent.PriorityBlockingQueue#PriorityBlockingQueue(int, Comparator)\n * @see java.util.PriorityQueue\n * @see java.util.PriorityQueue#PriorityQueue(int, Comparator)\n * @see JdkExecutorTtlTransformlet\n */\npublic class PriorityBlockingQueueTtlTransformlet implements TtlTransformlet {\n    private static final Logger logger = Logger.getLogger(PriorityBlockingQueueTtlTransformlet.class);\n\n    private static final String PRIORITY_BLOCKING_QUEUE_CLASS_NAME = \"java.util.concurrent.PriorityBlockingQueue\";\n    private static final String PRIORITY_QUEUE_CLASS_NAME = \"java.util.PriorityQueue\";\n    private static final String COMPARATOR_FIELD_NAME = \"comparator\";\n\n    @Override\n    public void doTransform(@NonNull ClassInfo classInfo) throws IOException, CannotCompileException, NotFoundException {\n        final String className = classInfo.getClassName();\n\n        if (PRIORITY_BLOCKING_QUEUE_CLASS_NAME.equals(className)) {\n            updatePriorityBlockingQueueClass(classInfo.getCtClass());\n            classInfo.setModified();\n        }\n\n        if (PRIORITY_QUEUE_CLASS_NAME.equals(className)) {\n            updateBlockingQueueClass(classInfo.getCtClass());\n            classInfo.setModified();\n        }\n    }\n\n    private void updatePriorityBlockingQueueClass(@NonNull final CtClass clazz) throws CannotCompileException, NotFoundException {\n        if (!haveComparatorField(clazz)) {\n            // In Java 6, PriorityBlockingQueue implementation do not have field comparator,\n            // need transform more fundamental class PriorityQueue\n            logger.info(PRIORITY_BLOCKING_QUEUE_CLASS_NAME + \" do not have field \" + COMPARATOR_FIELD_NAME +\n                    \", transform \" + PRIORITY_QUEUE_CLASS_NAME + \" instead.\");\n            return;\n        }\n\n        modifyConstructors(clazz);\n    }\n\n    private void updateBlockingQueueClass(@NonNull final CtClass clazz) throws CannotCompileException, NotFoundException {\n        final CtClass classPriorityBlockingQueue = clazz.getClassPool().getCtClass(PRIORITY_BLOCKING_QUEUE_CLASS_NAME);\n        if (haveComparatorField(classPriorityBlockingQueue)) return;\n\n        logger.info(PRIORITY_BLOCKING_QUEUE_CLASS_NAME + \" do not have field \" + COMPARATOR_FIELD_NAME +\n                \", so need transform \" + PRIORITY_QUEUE_CLASS_NAME);\n        modifyConstructors(clazz);\n    }\n\n    private static boolean haveComparatorField(CtClass clazz) {\n        try {\n            clazz.getDeclaredField(COMPARATOR_FIELD_NAME);\n            return true;\n        } catch (NotFoundException e) {\n            return false;\n        }\n    }\n\n    /**\n     * wrap comparator field in constructors\n     */\n    private static final String CODE = \"this.\" + COMPARATOR_FIELD_NAME + \" = \"\n            + PriorityBlockingQueueTtlTransformlet.class.getName() +\n            \".overwriteComparatorField$by$ttl(this.\" + COMPARATOR_FIELD_NAME + \");\";\n\n    /**\n     * @see #overwriteComparatorField$by$ttl(Comparator)\n     */\n    private static void modifyConstructors(@NonNull CtClass clazz) throws NotFoundException, CannotCompileException {\n        for (CtConstructor constructor : clazz.getDeclaredConstructors()) {\n            logger.info(\"insert code after constructor \" + signatureOfMethod(constructor) + \" of class \" +\n                    constructor.getDeclaringClass().getName() + \": \" + CODE);\n\n            constructor.insertAfter(CODE);\n        }\n    }\n\n    /**\n     * @see TtlExecutors#getTtlRunnableUnwrapComparator(Comparator)\n     */\n    public static Comparator<Runnable> overwriteComparatorField$by$ttl(Comparator<Runnable> comparator) {\n        if (comparator == null) return TtlExecutors.getTtlRunnableUnwrapComparatorForComparableRunnable();\n\n        return TtlExecutors.getTtlRunnableUnwrapComparator(comparator);\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/TimerTaskTtlTransformlet.java",
    "content": "package com.alibaba.ttl3.agent.transformlet.internal;\n\nimport com.alibaba.ttl3.agent.logging.Logger;\nimport com.alibaba.ttl3.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl3.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport javassist.*;\n\nimport java.io.IOException;\n\nimport static com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper.*;\n\n/**\n * {@link TtlTransformlet} for {@link java.util.TimerTask}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author wuwen5 (wuwen.55 at aliyun dot com)\n * @see java.util.TimerTask\n * @see java.util.Timer\n */\npublic final class TimerTaskTtlTransformlet implements TtlTransformlet {\n    private static final Logger logger = Logger.getLogger(TimerTaskTtlTransformlet.class);\n\n    private static final String TIMER_TASK_CLASS_NAME = \"java.util.TimerTask\";\n    private static final String RUN_METHOD_NAME = \"run\";\n\n    @Override\n    public void doTransform(@NonNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException {\n        // work-around ClassCircularityError:\n        if (isClassAtPackageJavaUtil(classInfo.getClassName())) return;\n\n        // TimerTask class is checked by above logic.\n        //\n        // if (TIMER_TASK_CLASS_NAME.equals(classInfo.getClassName())) return; // No need transform TimerTask class\n\n        final CtClass clazz = classInfo.getCtClass();\n\n        if (clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() || clazz.isAnnotation()) {\n            return;\n        }\n        // class contains method `void run()` ?\n        try {\n            final CtMethod runMethod = clazz.getDeclaredMethod(RUN_METHOD_NAME, new CtClass[0]);\n            if (!CtClass.voidType.equals(runMethod.getReturnType())) return;\n        } catch (NotFoundException e) {\n            return;\n        }\n        if (!clazz.subclassOf(clazz.getClassPool().get(TIMER_TASK_CLASS_NAME))) return;\n\n        logger.info(\"Transforming class \" + classInfo.getClassName());\n\n        updateTimerTaskClass(clazz);\n        classInfo.setModified();\n    }\n\n    /**\n     * @see TtlTransformletHelper#doCaptureIfNotTtlEnhanced(Object)\n     */\n    private void updateTimerTaskClass(@NonNull final CtClass clazz) throws CannotCompileException, NotFoundException {\n        final String className = clazz.getName();\n\n        // add new field\n        final String capturedFieldName = \"captured$field$added$by$ttl\";\n        final CtField capturedField = CtField.make(\"private final Object \" + capturedFieldName + \";\", clazz);\n        clazz.addField(capturedField, \"com.alibaba.ttl3.agent.transformlet.helper.TtlTransformletHelper.doCaptureIfNotTtlEnhanced(this);\");\n        logger.info(\"add new field \" + capturedFieldName + \" to class \" + className);\n\n        final CtMethod runMethod = clazz.getDeclaredMethod(RUN_METHOD_NAME, new CtClass[0]);\n\n        final String beforeCode = \"Object backup = com.alibaba.ttl3.transmitter.Transmitter.replay(\" + capturedFieldName + \");\";\n        final String finallyCode = \"com.alibaba.ttl3.transmitter.Transmitter.restore(backup);\";\n\n        final String code = addTryFinallyToMethod(runMethod, beforeCode, finallyCode);\n        logger.info(\"insert code around method \" + signatureOfMethod(runMethod) + \" of class \" + clazz.getName() + \": \" + code);\n    }\n}\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/internal/package-info.java",
    "content": "/**\n * TTL built-in {@code Transformlet} implementations.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.agent.transformlet.internal.JdkExecutorTtlTransformlet\n * @see com.alibaba.ttl3.agent.transformlet.internal.ForkJoinTtlTransformlet\n * @see com.alibaba.ttl3.agent.transformlet.internal.TimerTaskTtlTransformlet\n * @see com.alibaba.ttl3.agent.transformlet.TtlTransformlet\n */\npackage com.alibaba.ttl3.agent.transformlet.internal;\n"
  },
  {
    "path": "ttl-agent/src/main/java/com/alibaba/ttl3/agent/transformlet/package-info.java",
    "content": "/**\n * TTL {@code Transformlet} API for TTL Agent extension {@code Transformlet} development.\n * <p>\n * TTL built-in {@code Transformlet} implementations is in the package {@link com.alibaba.ttl3.agent.transformlet.internal}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.agent.transformlet.TtlTransformlet\n */\npackage com.alibaba.ttl3.agent.transformlet;\n"
  },
  {
    "path": "ttl-bom/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<!--\n\t\tMaven BOM Template\n\t\thttps://github.com/anliksim/maven-template-bom\n\t-->\n\t<groupId>com.alibaba.ttl3</groupId>\n\t<artifactId>ttl-bom</artifactId>\n\t<version>3.x-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<name>${project.artifactId}</name>\n\t<description>${project.artifactId}</description>\n\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache 2</name>\n\t\t\t<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t\t<comments>A business-friendly OSS license</comments>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<connection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</connection>\n\t\t<developerConnection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</developerConnection>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t</scm>\n\t<issueManagement>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/issues</url>\n\t\t<system>GitHub Issues</system>\n\t</issueManagement>\n\t<ciManagement>\n\t\t<system>GitHub Actions</system>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/actions</url>\n\t</ciManagement>\n\t<organization>\n\t\t<name>Alibaba</name>\n\t\t<url>https://www.alibaba.com</url>\n\t</organization>\n\t<developers>\n\t\t<developer>\n\t\t\t<name>Jerry Lee</name>\n\t\t\t<id>oldratlee</id>\n\t\t\t<email>oldratlee(AT)gmail(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/oldratlee</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t</developers>\n\n\t<properties>\n\t\t<jacoco.skip>true</jacoco.skip>\n\t</properties>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.alibaba.ttl3</groupId>\n\t\t\t\t<artifactId>ttl-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>com.alibaba.ttl3</groupId>\n\t\t\t\t<artifactId>ttl-agent</artifactId>\n\t\t\t\t<version>${project.version}</version>\n\t\t\t</dependency>\n\n\t\t\t<dependency>\n\t\t\t\t<groupId>com.alibaba.ttl3</groupId>\n\t\t\t\t<artifactId>ttl-kotlin</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>com.alibaba</groupId>\n\t\t\t\t<artifactId>transmittable-thread-local</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<distributionManagement>\n\t\t<snapshotRepository>\n\t\t\t<id>ossrh</id>\n\t\t\t<url>https://oss.sonatype.org/content/repositories/snapshots</url>\n\t\t</snapshotRepository>\n\t</distributionManagement>\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<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t\t<version>3.3.1</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t\t<version>3.8.0</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t\t<version>3.1.3</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<groupId>org.jacoco</groupId>\n\t\t\t\t\t<artifactId>jacoco-maven-plugin</artifactId>\n\t\t\t\t\t<version>0.8.12</version>\n\t\t\t\t</plugin>\n\t\t\t</plugins>\n\t\t</pluginManagement>\n\t</build>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>gen-sign</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t\t\t<version>3.2.7</version>\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>sign-artifacts</id>\n\t\t\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t\t\t</goals>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>deploy-settings</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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.sonatype.plugins</groupId>\n\t\t\t\t\t\t<artifactId>nexus-staging-maven-plugin</artifactId>\n\t\t\t\t\t\t<version>1.7.0</version>\n\t\t\t\t\t\t<extensions>true</extensions>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<serverId>ossrh</serverId>\n\t\t\t\t\t\t\t<nexusUrl>https://oss.sonatype.org/</nexusUrl>\n\t\t\t\t\t\t\t<autoReleaseAfterClose>true</autoReleaseAfterClose>\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": "ttl-core/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.ttl3</groupId>\n\t\t<artifactId>ttl3-parent</artifactId>\n\t\t<version>3.x-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\n\t<artifactId>ttl-core</artifactId>\n\t<packaging>jar</packaging>\n\t<name>TransmittableThreadLocal(TTL)</name>\n\t<description>\n\t\t📌 The missing Java™ std lib(simple &amp; 0-dependency) for framework/middleware,\n\t\tprovide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.\n\t</description>\n\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t<inceptionYear>2022</inceptionYear>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache 2</name>\n\t\t\t<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t\t<comments>A business-friendly OSS license</comments>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<connection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</connection>\n\t\t<developerConnection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</developerConnection>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t</scm>\n\t<issueManagement>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/issues</url>\n\t\t<system>GitHub Issues</system>\n\t</issueManagement>\n\t<ciManagement>\n\t\t<system>GitHub Actions</system>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/actions</url>\n\t</ciManagement>\n\t<organization>\n\t\t<name>Alibaba</name>\n\t\t<url>https://www.alibaba.com</url>\n\t</organization>\n\t<developers>\n\t\t<developer>\n\t\t\t<name>Jerry Lee</name>\n\t\t\t<id>oldratlee</id>\n\t\t\t<email>oldratlee(AT)gmail(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/oldratlee</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<name>Yang Fang</name>\n\t\t\t<id>driventokill</id>\n\t\t\t<email>snoop(DOT)fy(AT)gmail(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/driventokill</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<name>wuwen</name>\n\t\t\t<id>wuwen5</id>\n\t\t\t<email>wuwen.55(AT)aliyun(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/wuwen5</url>\n\t\t\t<organization>ofpay</organization>\n\t\t\t<organizationUrl>https://www.ofpay.com</organizationUrl>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<name>David Dai</name>\n\t\t\t<id>LNAmp</id>\n\t\t\t<email>351450944(AT)qq(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/LNAmp</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t</developers>\n\n\t<dependencies>\n\t\t<!-- test scope dependencies -->\n\t\t<dependency>\n\t\t\t<groupId>io.reactivex.rxjava2</groupId>\n\t\t\t<artifactId>rxjava</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.reactivex.rxjava2</groupId>\n\t\t\t<artifactId>rxkotlin</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n</project>\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/crr/TransmitCallback.java",
    "content": "package com.alibaba.crr;\n\n/**\n * The callback of {@link Transmittable} process.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see Transmittable\n */\npublic interface TransmitCallback {\n    /**\n     * @see Transmittable#replay(Object)\n     */\n    default void beforeReplay() {\n    }\n\n    /**\n     * @see Transmittable#replay(Object)\n     */\n    default void afterReplay() {\n    }\n\n    /**\n     * @see Transmittable#restore(Object)\n     */\n    default void beforeRestore() {\n    }\n\n    /**\n     * @see Transmittable#restore(Object)\n     */\n    default void afterRestore() {\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/crr/Transmittable.java",
    "content": "package com.alibaba.crr;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\n/**\n * Transmittance process is represented by methods {@link #capture()} =&gt;\n * {@link #replay(Object)} =&gt; {@link #restore(Object)} (aka {@code CRR} operations).\n *\n * @param <C> the capture data type of transmittance\n * @param <B> the backup data type of transmittance\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\npublic interface Transmittable<C, B> {\n    /**\n     * Capture.\n     * <p>\n     * <B><I>NOTE:</I></B><br>\n     * do NOT return {@code null}.\n     *\n     * @return the capture data of transmittance\n     */\n    @NonNull\n    C capture();\n\n    /**\n     * Replay.\n     * <p>\n     * <B><I>NOTE:</I></B><br>\n     * do NOT return {@code null}.\n     *\n     * @param captured the capture data of transmittance, the return value of method {@link #capture()}\n     * @return the backup data of transmittance\n     */\n    @NonNull\n    B replay(@NonNull C captured);\n\n    /**\n     * Clear.\n     * <p>\n     * <B><I>NOTE:</I></B><br>\n     * do NOT return {@code null}.\n     * <p>\n     * Semantically, the code {@code `B backup = clear();`} is same as {@code `B backup = replay(EMPTY_CAPTURE);`}.\n     * <p>\n     * The reason for providing this method is:\n     * <ol>\n     * <li>lead to more readable code</li>\n     * <li>need not provide the constant {@code EMPTY_CAPTURE}.</li>\n     * </ol>\n     *\n     * @return the backup data of transmittance\n     */\n    @NonNull\n    B clear();\n\n    /**\n     * Restore.\n     *\n     * @param backup the backup data of transmittance, the return value of methods {@link #replay(Object)} or {@link #clear()}\n     * @see #replay(Object)\n     * @see #clear()\n     */\n    void restore(@NonNull B backup);\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/crr/composite/Backup.java",
    "content": "package com.alibaba.crr.composite;\n\nimport org.jetbrains.annotations.ApiStatus;\n\n/**\n * The composite backup data type of {@link CompositeTransmittable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see CompositeTransmittable\n */\n@ApiStatus.NonExtendable\npublic interface Backup {\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/crr/composite/Capture.java",
    "content": "package com.alibaba.crr.composite;\n\nimport org.jetbrains.annotations.ApiStatus;\n\n/**\n * The composite capture data type of {@link CompositeTransmittable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see CompositeTransmittable\n */\n@ApiStatus.NonExtendable\npublic interface Capture {\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/crr/composite/CompositeTransmitCallback.java",
    "content": "package com.alibaba.crr.composite;\n\nimport com.alibaba.crr.TransmitCallback;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport static com.alibaba.ttl3.internal.util.Utils.propagateIfFatal;\n\n/**\n * Composite TransmitCallback.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see TransmitCallback\n */\npublic final class CompositeTransmitCallback {\n    private static final Logger logger = Logger.getLogger(CompositeTransmitCallback.class.getName());\n\n    private final Set<TransmitCallback> registeredTransmitCallbackSet = new CopyOnWriteArraySet<>();\n\n    Object beforeReplay() {\n        Set<TransmitCallback> callbacks = new HashSet<>(registeredTransmitCallbackSet);\n        for (TransmitCallback cb : callbacks) {\n            try {\n                cb.beforeReplay();\n            } catch (Throwable t) {\n                propagateIfFatal(t);\n                if (logger.isLoggable(Level.WARNING)) {\n                    logger.log(Level.WARNING, \"exception when beforeReplay for transmittableCallback \" + cb +\n                            \"(class \" + cb.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                }\n            }\n        }\n        return callbacks;\n    }\n\n    Object afterReplay(Object data) {\n        @SuppressWarnings(\"unchecked\")\n        Set<TransmitCallback> callbacks = (Set<TransmitCallback>) data;\n        for (TransmitCallback cb : callbacks) {\n            try {\n                cb.afterReplay();\n            } catch (Throwable t) {\n                propagateIfFatal(t);\n                if (logger.isLoggable(Level.WARNING)) {\n                    logger.log(Level.WARNING, \"exception when afterReplay for transmittableCallback \" + cb +\n                            \"(class \" + cb.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                }\n            }\n        }\n        return data;\n    }\n\n    Object beforeRestore(Object data) {\n        @SuppressWarnings(\"unchecked\")\n        Set<TransmitCallback> callbacks = (Set<TransmitCallback>) data;\n        for (TransmitCallback cb : callbacks) {\n            try {\n                cb.beforeRestore();\n            } catch (Throwable t) {\n                propagateIfFatal(t);\n                if (logger.isLoggable(Level.WARNING)) {\n                    logger.log(Level.WARNING, \"exception when beforeRestore for transmittableCallback \" + cb +\n                            \"(class \" + cb.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                }\n            }\n        }\n        return data;\n    }\n\n    void afterRestore(Object data) {\n        @SuppressWarnings(\"unchecked\")\n        Set<TransmitCallback> callbacks = (Set<TransmitCallback>) data;\n        for (TransmitCallback cb : callbacks) {\n            try {\n                cb.afterRestore();\n            } catch (Throwable t) {\n                propagateIfFatal(t);\n                if (logger.isLoggable(Level.WARNING)) {\n                    logger.log(Level.WARNING, \"exception when afterRestore for transmittableCallback \" + cb +\n                            \"(class \" + cb.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                }\n            }\n        }\n    }\n\n\n    /**\n     * Register the {@link TransmitCallback}.\n     *\n     * @return true if the input callback is not registered\n     * @see #unregisterCallback(TransmitCallback)\n     */\n    public boolean registerCallback(@NonNull TransmitCallback callback) {\n        return registeredTransmitCallbackSet.add(callback);\n    }\n\n    /**\n     * Unregister the {@link TransmitCallback}.\n     *\n     * @return true if the input callback is registered\n     * @see #registerCallback(TransmitCallback)\n     */\n    public boolean unregisterCallback(@NonNull TransmitCallback callback) {\n        return registeredTransmitCallbackSet.remove(callback);\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/crr/composite/CompositeTransmittable.java",
    "content": "package com.alibaba.crr.composite;\n\nimport com.alibaba.crr.Transmittable;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport static com.alibaba.ttl3.internal.util.Utils.newHashMap;\nimport static com.alibaba.ttl3.internal.util.Utils.propagateIfFatal;\n\n/**\n * {@link CompositeTransmittable} transmit all {@link Transmittable}\n * registered by {@link #registerTransmittable(Transmittable)}.\n * <p>\n * Transmittance is completed by methods {@link #capture()} =&gt;\n * {@link #replay(Capture)} =&gt; {@link #restore(Backup)} (aka {@code CRR} operations).\n * <p>\n * <B><I>CAUTION:</I></B><br>\n * This implementation just ignore all exception thrown by\n * {@code CRR} operations of registered {@link Transmittable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\npublic final class CompositeTransmittable implements Transmittable<Capture, Backup> {\n    private static final Logger logger = Logger.getLogger(CompositeTransmittable.class.getName());\n\n    private final Set<Transmittable<Object, Object>> registeredTransmittableSet = new CopyOnWriteArraySet<>();\n\n    private final CompositeTransmitCallback callback;\n\n    public CompositeTransmittable(CompositeTransmitCallback callback) {\n        this.callback = callback;\n    }\n\n    /**\n     * Capture all {@link Transmittable}.\n     *\n     * @return the captured values\n     */\n    @NonNull\n    public Capture capture() {\n        final HashMap<Transmittable<Object, Object>, Object> transmit2Value = newHashMap(registeredTransmittableSet.size());\n        for (Transmittable<Object, Object> transmittable : registeredTransmittableSet) {\n            try {\n                transmit2Value.put(transmittable, transmittable.capture());\n            } catch (Throwable t) {\n                propagateIfFatal(t);\n                if (logger.isLoggable(Level.WARNING)) {\n                    logger.log(Level.WARNING, \"exception when capture for transmittable \" + transmittable +\n                            \"(class \" + transmittable.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                }\n            }\n        }\n        return new Snapshot(transmit2Value, null);\n    }\n\n    /**\n     * Replay the captured values from {@link #capture()},\n     * and return the backup values before replay.\n     *\n     * @param captured captured values {@link #capture()}\n     * @return the backup values before replay\n     * @see #capture()\n     */\n    @NonNull\n    public Backup replay(@NonNull Capture captured) {\n        final Object data = callback.beforeReplay();\n\n        final Snapshot capturedSnapshot = (Snapshot) captured;\n        final HashMap<Transmittable<Object, Object>, Object> transmit2Value = newHashMap(capturedSnapshot.transmit2Value.size());\n        for (Map.Entry<Transmittable<Object, Object>, Object> entry : capturedSnapshot.transmit2Value.entrySet()) {\n            Transmittable<Object, Object> transmittable = entry.getKey();\n            try {\n                Object transmitCaptured = entry.getValue();\n                transmit2Value.put(transmittable, transmittable.replay(transmitCaptured));\n            } catch (Throwable t) {\n                propagateIfFatal(t);\n                if (logger.isLoggable(Level.WARNING)) {\n                    logger.log(Level.WARNING, \"exception when replay for transmittable \" + transmittable +\n                            \"(class \" + transmittable.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                }\n            }\n        }\n\n        final Object afterData = callback.afterReplay(data);\n        return new Snapshot(transmit2Value, afterData);\n    }\n\n    /**\n     * Clear all values, and return the backup values before clear.\n     * <p>\n     * Semantically, the code {@code `Object backup = clear();`} is same as {@code `Object backup = replay(EMPTY_CAPTURE);`}.\n     * <p>\n     * The reason for providing this method is:\n     *\n     * <ol>\n     * <li>lead to more readable code</li>\n     * <li>need not provide the constant {@code EMPTY_CAPTURE}.</li>\n     * </ol>\n     *\n     * @return the backup values before clear\n     * @see #replay(Capture)\n     */\n    @NonNull\n    public Backup clear() {\n        final Object data = callback.beforeReplay();\n\n        final HashMap<Transmittable<Object, Object>, Object> transmit2Value = newHashMap(registeredTransmittableSet.size());\n        for (Transmittable<Object, Object> transmittable : registeredTransmittableSet) {\n            try {\n                transmit2Value.put(transmittable, transmittable.clear());\n            } catch (Throwable t) {\n                propagateIfFatal(t);\n                if (logger.isLoggable(Level.WARNING)) {\n                    logger.log(Level.WARNING, \"exception when clear for transmittable \" + transmittable +\n                            \"(class \" + transmittable.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                }\n            }\n        }\n\n        final Object afterData = callback.afterReplay(data);\n        return new Snapshot(transmit2Value, afterData);\n    }\n\n    /**\n     * Restore the backup values from {@link #replay(Capture)}/{@link #clear()}.\n     *\n     * @param backup the backup values from {@link #replay(Capture)}/{@link #clear()}\n     * @see #replay(Capture)\n     * @see #clear()\n     */\n    public void restore(@NonNull Backup backup) {\n        final Snapshot snapshot = (Snapshot) backup;\n        final Object data = callback.beforeRestore(snapshot.data);\n\n        for (Map.Entry<Transmittable<Object, Object>, Object> entry : snapshot.transmit2Value.entrySet()) {\n            Transmittable<Object, Object> transmittable = entry.getKey();\n            try {\n                Object transmitBackup = entry.getValue();\n                transmittable.restore(transmitBackup);\n            } catch (Throwable t) {\n                propagateIfFatal(t);\n                if (logger.isLoggable(Level.WARNING)) {\n                    logger.log(Level.WARNING, \"exception when restore for transmittable \" + transmittable +\n                            \"(class \" + transmittable.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                }\n            }\n        }\n\n        callback.afterRestore(data);\n    }\n\n    private static class Snapshot implements Capture, Backup {\n        final HashMap<Transmittable<Object, Object>, Object> transmit2Value;\n        final Object data;\n\n        Snapshot(HashMap<Transmittable<Object, Object>, Object> transmit2Value, Object data) {\n            this.transmit2Value = transmit2Value;\n            this.data = data;\n        }\n    }\n\n\n    /**\n     * Register the Transmittable.\n     *\n     * @param <C> the Transmittable capture data type\n     * @param <B> the Transmittable backup data type\n     * @return true if the input Transmittable is not registered\n     * @see #unregisterTransmittable(Transmittable)\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <C, B> boolean registerTransmittable(@NonNull Transmittable<C, B> transmittable) {\n        return registeredTransmittableSet.add((Transmittable<Object, Object>) transmittable);\n    }\n\n    /**\n     * Unregister the Transmittable.\n     *\n     * @param <C> the Transmittable capture data type\n     * @param <B> the Transmittable backup data type\n     * @return true if the input transmittable is registered\n     * @see #registerTransmittable(Transmittable)\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <C, B> boolean unregisterTransmittable(@NonNull Transmittable<C, B> transmittable) {\n        return registeredTransmittableSet.remove((Transmittable<Object, Object>) transmittable);\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/crr/composite/package-info.java",
    "content": "/**\n * Provide composite transmittance implementation\n * {@link com.alibaba.crr.composite.CompositeTransmittable}\n * for {@link com.alibaba.crr.Transmittable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.crr.composite.CompositeTransmittable\n * @see com.alibaba.crr.Transmittable\n */\npackage com.alibaba.crr.composite;\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/crr/package-info.java",
    "content": "/**\n * The base independent abstraction of {@code CRR}\n * transmittance({@code interface} {@link com.alibaba.crr.Transmittable}),\n * and provide a common related component implementation\n * {@link com.alibaba.crr.composite.CompositeTransmittable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.crr.Transmittable\n * @see com.alibaba.crr.composite.CompositeTransmittable\n */\npackage com.alibaba.crr;\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/TransmittableThreadLocal.java",
    "content": "package com.alibaba.ttl3;\n\nimport com.alibaba.ttl3.executor.TtlExecutors;\nimport com.alibaba.ttl3.transmitter.Transmittee;\nimport com.alibaba.ttl3.transmitter.TransmitteeRegistry;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport javax.annotation.ParametersAreNonnullByDefault;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.WeakHashMap;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport static com.alibaba.ttl3.internal.util.Utils.newHashMap;\n\n/**\n * {@link TransmittableThreadLocal}({@code TTL}) can transmit the value from the thread of submitting task\n * to the thread of executing task even using thread pooling components.\n * <p>\n * <b>Note</b>:<br>\n * {@link TransmittableThreadLocal} extends {@link InheritableThreadLocal},\n * so {@link TransmittableThreadLocal} first is a {@link InheritableThreadLocal}.<br>\n * If the <b>inheritable</b> ability from {@link InheritableThreadLocal} has <b>potential leaking problem</b>,\n * you can disable the <b>inheritable</b> ability:\n * <p>\n * ❶ For thread pooling components({@link java.util.concurrent.ThreadPoolExecutor},\n * {@link java.util.concurrent.ForkJoinPool}), Inheritable feature <b>should never</b> happen,\n * since threads in thread pooling components is pre-created and pooled, these threads is <b>neutral</b> to biz logic/data.\n * <br>\n * Disable inheritable for thread pooling components by wrapping thread factories using methods\n * {@link TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory) getDisableInheritableThreadFactory} /\n * {@link TtlExecutors#getDefaultDisableInheritableForkJoinWorkerThreadFactory() getDefaultDisableInheritableForkJoinWorkerThreadFactory}.\n * <br>\n * Or you can turn on \"disable inheritable for thread pool\" by {@code TTL Java Agent}\n * to wrap thread factories for thread pooling components automatically and transparently.\n * <p>\n * ❷ In other cases, disable inheritable by overriding method {@link #childValue(Object)}.\n * <br>\n * Whether the value should be inheritable or not can be controlled by the data owner,\n * disable it <b>carefully</b> when data owner have a clear idea.\n * <pre>{@code\n * TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>() {\n *     protected String childValue(String parentValue) {\n *         return initialValue();\n *     }\n * }}</pre>\n * <p>\n * More discussion about \"disable the <b>inheritable</b> ability\"\n * see <a href=\"https://github.com/alibaba/transmittable-thread-local/issues/100\">\n * issue #100: disable Inheritable when it's not necessary and buggy</a>.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author Yang Fang (snoop dot fy at gmail dot com)\n * @see <a href=\"https://github.com/alibaba/transmittable-thread-local\">user guide docs and code repo of TransmittableThreadLocal(TTL)</a>\n * @see TtlRunnable\n * @see TtlCallable\n * @see TtlExecutors\n * @see TtlExecutors#getTtlExecutor(java.util.concurrent.Executor)\n * @see TtlExecutors#getTtlExecutorService(java.util.concurrent.ExecutorService)\n * @see TtlExecutors#getTtlScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)\n * @see TtlExecutors#getDefaultDisableInheritableThreadFactory()\n * @see TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)\n * @see TtlExecutors#getDefaultDisableInheritableForkJoinWorkerThreadFactory()\n * @see TtlExecutors#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory)\n */\npublic class TransmittableThreadLocal<T> extends InheritableThreadLocal<T> {\n    private final boolean disableIgnoreNullValueSemantics;\n\n    /**\n     * Default constructor. Create a {@link TransmittableThreadLocal} instance with \"Ignore-Null-Value Semantics\".\n     * <p>\n     * About \"Ignore-Null-Value Semantics\":\n     *\n     * <ol>\n     *     <li>If value is {@code null}(check by {@link #get()} method), do NOT transmit this {@code ThreadLocal}.</li>\n     *     <li>If set {@code null} value, also remove value(invoke {@link #remove()} method).</li>\n     * </ol>\n     * <p>\n     * This is a pragmatic design decision:\n     * <ol>\n     * <li>use explicit value type rather than {@code null} value to express biz intent.</li>\n     * <li>safer and more robust code(avoid {@code NPE} risk).</li>\n     * </ol>\n     * <p>\n     * So it's strongly not recommended to use {@code null} value.\n     * <p>\n     * But the behavior of \"Ignore-Null-Value Semantics\" is NOT compatible with\n     * {@link ThreadLocal} and {@link InheritableThreadLocal},\n     * you can disable this behavior/semantics via using constructor {@link #TransmittableThreadLocal(boolean)}\n     * and setting parameter {@code disableIgnoreNullValueSemantics} to {@code true}.\n     * <p>\n     * More discussion about \"Ignore-Null-Value Semantics\" see\n     * <a href=\"https://github.com/alibaba/transmittable-thread-local/issues/157\">Issue #157</a>.\n     *\n     * @see #TransmittableThreadLocal(boolean)\n     */\n    public TransmittableThreadLocal() {\n        this(false);\n    }\n\n    /**\n     * Constructor, create a {@link TransmittableThreadLocal} instance\n     * with parameter {@code disableIgnoreNullValueSemantics} to control \"Ignore-Null-Value Semantics\".\n     *\n     * @param disableIgnoreNullValueSemantics disable \"Ignore-Null-Value Semantics\"\n     * @see #TransmittableThreadLocal()\n     */\n    public TransmittableThreadLocal(boolean disableIgnoreNullValueSemantics) {\n        this.disableIgnoreNullValueSemantics = disableIgnoreNullValueSemantics;\n    }\n\n    /**\n     * Creates a transmittable thread local variable.\n     * The initial value({@link #initialValue()}) of the variable is\n     * determined by invoking the {@link #get()} method on the {@code Supplier}.\n     *\n     * @param <S>      the type of the thread local's value\n     * @param supplier the supplier to be used to determine the initial value\n     * @return a new transmittable thread local variable\n     * @throws NullPointerException if the specified supplier is null\n     * @see #withInitialAndGenerator(Supplier, UnaryOperator)\n     */\n    @NonNull\n    @SuppressWarnings(\"ConstantConditions\")\n    public static <S> TransmittableThreadLocal<S> withInitial(@NonNull Supplier<? extends S> supplier) {\n        if (supplier == null) throw new NullPointerException(\"supplier is null\");\n\n        return new SuppliedTransmittableThreadLocal<>(supplier, null, null);\n    }\n\n    /**\n     * Creates a transmittable thread local variable.\n     * The initial value({@link #initialValue()}) of the variable is\n     * determined by invoking the {@link #get()} method on the {@code Supplier};\n     * and the child value({@link #childValue(Object)}) and the transmittee value({@link #transmitteeValue(Object)}) of the variable is\n     * determined by invoking the {@link UnaryOperator#apply(Object)} method on the {@code UnaryOperator}.\n     *\n     * @param <S>                                       the type of the thread local's value\n     * @param supplier                                  the supplier to be used to determine the initial value\n     * @param generatorForChildValueAndTransmitteeValue the value generator to be used to determine the child value and the transmittee value\n     * @return a new transmittable thread local variable\n     * @throws NullPointerException if the specified supplier or value generator is null\n     * @see #withInitial(Supplier)\n     */\n    @NonNull\n    @ParametersAreNonnullByDefault\n    @SuppressWarnings(\"ConstantConditions\")\n    public static <S> TransmittableThreadLocal<S> withInitialAndGenerator(Supplier<? extends S> supplier, UnaryOperator<S> generatorForChildValueAndTransmitteeValue) {\n        if (supplier == null) throw new NullPointerException(\"supplier is null\");\n        if (generatorForChildValueAndTransmitteeValue == null) throw new NullPointerException(\"value generator is null\");\n\n        return new SuppliedTransmittableThreadLocal<>(supplier, generatorForChildValueAndTransmitteeValue, generatorForChildValueAndTransmitteeValue);\n    }\n\n    /**\n     * Creates a transmittable thread local variable.\n     * The initial value({@link #initialValue()}) of the variable is\n     * determined by invoking the {@link #get()} method on the {@code Supplier};\n     * and the child value({@link #childValue(Object)})}) and the transmittee value({@link #transmitteeValue(Object)}) of the variable is\n     * determined by invoking the {@link UnaryOperator#apply(Object)} method on the {@code UnaryOperator}.\n     * <p>\n     * <B><I>NOTE:</I></B><br>\n     * Recommend use {@link #withInitialAndGenerator(Supplier, UnaryOperator)} instead of this method.\n     * In most cases, the logic of determining the child value({@link #childValue(Object)})\n     * and the transmittee value({@link #transmitteeValue(Object)}) should be the same.\n     *\n     * @param <S>                          the type of the thread local's value\n     * @param supplier                     the supplier to be used to determine the initial value\n     * @param generatorForChildValue       the value generator to be used to determine the child value\n     * @param generatorForTransmitteeValue the value generator to be used to determine the transmittee value\n     * @return a new transmittable thread local variable\n     * @throws NullPointerException if the specified supplier or value generator is null\n     * @see #withInitial(Supplier)\n     * @see #withInitialAndGenerator(Supplier, UnaryOperator)\n     */\n    @NonNull\n    @ParametersAreNonnullByDefault\n    @SuppressWarnings(\"ConstantConditions\")\n    public static <S> TransmittableThreadLocal<S> withInitialAndGenerator(Supplier<? extends S> supplier, UnaryOperator<S> generatorForChildValue, UnaryOperator<S> generatorForTransmitteeValue) {\n        if (supplier == null) throw new NullPointerException(\"supplier is null\");\n        if (generatorForChildValue == null) throw new NullPointerException(\"value generator for child value is null\");\n        if (generatorForTransmitteeValue == null) throw new NullPointerException(\"value generator for transmittee value is null\");\n\n        return new SuppliedTransmittableThreadLocal<>(supplier, generatorForChildValue, generatorForTransmitteeValue);\n    }\n\n    /**\n     * An extension of ThreadLocal that obtains its initial value from the specified {@code Supplier}\n     * and obtains its child value and transmittee value from the specified generator.\n     */\n    private static final class SuppliedTransmittableThreadLocal<T> extends TransmittableThreadLocal<T> {\n        private final Supplier<? extends T> supplier;\n        private final UnaryOperator<T> generatorForChildValue;\n        private final UnaryOperator<T> generatorForTransmitteeValue;\n\n        SuppliedTransmittableThreadLocal(Supplier<? extends T> supplier, UnaryOperator<T> generatorForChildValue, UnaryOperator<T> generatorForTransmitteeValue) {\n            if (supplier == null) throw new NullPointerException(\"supplier is null\");\n            this.supplier = supplier;\n            this.generatorForChildValue = generatorForChildValue;\n            this.generatorForTransmitteeValue = generatorForTransmitteeValue;\n        }\n\n        @Override\n        protected T initialValue() {\n            return supplier.get();\n        }\n\n        @Override\n        protected T childValue(T parentValue) {\n            if (generatorForChildValue != null) return generatorForChildValue.apply(parentValue);\n            else return super.childValue(parentValue);\n        }\n\n        @Override\n        public T transmitteeValue(T parentValue) {\n            if (generatorForTransmitteeValue != null) return generatorForTransmitteeValue.apply(parentValue);\n            else return super.transmitteeValue(parentValue);\n        }\n    }\n\n    /**\n     * Computes the child's initial value for this transmittable thread-local\n     * variable as a function of the parent's value at the time the child\n     * thread is created. This method is called from within the parent\n     * thread before the child is started.\n     * <p>\n     * <b>Note</b>:<br>\n     * This method is overridden, and merely call {@link #transmitteeValue(Object)}.\n     * In most cases, the logic of determining the child value({@link #childValue(Object)})\n     * and the transmittee value({@link #transmitteeValue(Object)}) should be the same,\n     * so it's NOT recommended to override this method in subclass.\n     *\n     * @param parentValue the parent thread's value\n     * @return the child thread's initial value\n     */\n    @Override\n    protected T childValue(T parentValue) {\n        return transmitteeValue(parentValue);\n    }\n\n    /**\n     * Computes the value for this transmittable thread-local variable\n     * as a function of the source thread's value at the time the task\n     * Object is created.\n     * <p>\n     * This method is called from {@link TtlRunnable} or\n     * {@link TtlCallable} when it create, before the task is started.\n     * <p>\n     * <b>Note</b>:<br>\n     * This method merely returns reference of its source thread value(the shadow copy),\n     * and should be overridden if a different behavior is desired.\n     * It's recommended to override this method in subclass.\n     */\n    protected T transmitteeValue(T parentValue) {\n        return parentValue;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public final T get() {\n        T value = super.get();\n        if (disableIgnoreNullValueSemantics || value != null) addThisToHolder();\n        return value;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public final void set(T value) {\n        if (!disableIgnoreNullValueSemantics && value == null) {\n            // may set null to remove value\n            remove();\n        } else {\n            super.set(value);\n            addThisToHolder();\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public final void remove() {\n        removeThisFromHolder();\n        super.remove();\n    }\n\n    private void superRemove() {\n        super.remove();\n    }\n\n    private T getTransmitteeValue() {\n        return transmitteeValue(get());\n    }\n\n    // Note about the holder:\n    // 1. holder self is a InheritableThreadLocal(a *ThreadLocal*).\n    // 2. The type of value in the holder is WeakHashMap<TransmittableThreadLocal<Object>, ?>.\n    //    2.1 but the WeakHashMap is used as a *Set*:\n    //        the value of WeakHashMap is *always* null, and never used.\n    //    2.2 WeakHashMap support *null* value.\n    private static final InheritableThreadLocal<WeakHashMap<TransmittableThreadLocal<Object>, ?>> holder =\n            new InheritableThreadLocal<WeakHashMap<TransmittableThreadLocal<Object>, ?>>() {\n                @Override\n                protected WeakHashMap<TransmittableThreadLocal<Object>, ?> initialValue() {\n                    return new WeakHashMap<>();\n                }\n\n                @Override\n                protected WeakHashMap<TransmittableThreadLocal<Object>, ?> childValue(WeakHashMap<TransmittableThreadLocal<Object>, ?> parentValue) {\n                    return new WeakHashMap<>(parentValue);\n                }\n            };\n\n    @SuppressWarnings(\"unchecked\")\n    private void addThisToHolder() {\n        if (!holder.get().containsKey(this)) {\n            holder.get().put((TransmittableThreadLocal<Object>) this, null); // WeakHashMap supports null value.\n        }\n    }\n\n    private void removeThisFromHolder() {\n        holder.get().remove(this);\n    }\n\n\n    private static class TtlTransmittee implements Transmittee<HashMap<TransmittableThreadLocal<Object>, Object>, HashMap<TransmittableThreadLocal<Object>, Object>> {\n        @NonNull\n        @Override\n        public HashMap<TransmittableThreadLocal<Object>, Object> capture() {\n            final HashMap<TransmittableThreadLocal<Object>, Object> ttl2Value = newHashMap(holder.get().size());\n            for (TransmittableThreadLocal<Object> threadLocal : holder.get().keySet()) {\n                ttl2Value.put(threadLocal, threadLocal.getTransmitteeValue());\n            }\n            return ttl2Value;\n        }\n\n        @NonNull\n        @Override\n        public HashMap<TransmittableThreadLocal<Object>, Object> replay(@NonNull HashMap<TransmittableThreadLocal<Object>, Object> captured) {\n            final HashMap<TransmittableThreadLocal<Object>, Object> backup = newHashMap(holder.get().size());\n\n            for (final Iterator<TransmittableThreadLocal<Object>> iterator = holder.get().keySet().iterator(); iterator.hasNext(); ) {\n                TransmittableThreadLocal<Object> threadLocal = iterator.next();\n\n                // backup\n                backup.put(threadLocal, threadLocal.get());\n\n                // clear the TTL values that is not in captured\n                // avoid the extra TTL values after replay when run task\n                if (!captured.containsKey(threadLocal)) {\n                    iterator.remove();\n                    threadLocal.superRemove();\n                }\n            }\n\n            // set TTL values to captured\n            setTtlValuesTo(captured);\n\n            return backup;\n        }\n\n        @NonNull\n        @Override\n        public HashMap<TransmittableThreadLocal<Object>, Object> clear() {\n            return replay(newHashMap(0));\n        }\n\n        @Override\n        public void restore(@NonNull HashMap<TransmittableThreadLocal<Object>, Object> backup) {\n            for (final Iterator<TransmittableThreadLocal<Object>> iterator = holder.get().keySet().iterator(); iterator.hasNext(); ) {\n                TransmittableThreadLocal<Object> threadLocal = iterator.next();\n\n                // clear the TTL values that is not in backup\n                // avoid the extra TTL values after restore\n                if (!backup.containsKey(threadLocal)) {\n                    iterator.remove();\n                    threadLocal.superRemove();\n                }\n            }\n\n            // restore TTL values\n            setTtlValuesTo(backup);\n        }\n\n        private static void setTtlValuesTo(@NonNull HashMap<TransmittableThreadLocal<Object>, Object> ttlValues) {\n            for (Map.Entry<TransmittableThreadLocal<Object>, Object> entry : ttlValues.entrySet()) {\n                TransmittableThreadLocal<Object> threadLocal = entry.getKey();\n                threadLocal.set(entry.getValue());\n            }\n        }\n    }\n\n    private static final TtlTransmittee ttlTransmittee = new TtlTransmittee();\n\n    static {\n        TransmitteeRegistry.registerTransmittee(ttlTransmittee);\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/TtlCallable.java",
    "content": "package com.alibaba.ttl3;\n\nimport com.alibaba.crr.composite.Backup;\nimport com.alibaba.crr.composite.Capture;\nimport com.alibaba.ttl3.spi.TtlAttachments;\nimport com.alibaba.ttl3.spi.TtlAttachmentsDelegate;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\nimport com.alibaba.ttl3.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static com.alibaba.ttl3.transmitter.Transmitter.*;\n\n/**\n * {@link TtlCallable} decorate {@link Callable} to get {@link TransmittableThreadLocal} value\n * and transmit it to the time of {@link Callable} execution, needed when use {@link Callable} to thread pool.\n * <p>\n * Use factory method {@link #get(Callable)} to get decorated instance.\n * <p>\n * Other TTL Wrapper for common {@code Functional Interface} see {@link TtlWrappers}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.executor.TtlExecutors\n * @see TtlWrappers\n * @see java.util.concurrent.Executor\n * @see java.util.concurrent.ExecutorService\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ScheduledThreadPoolExecutor\n * @see java.util.concurrent.Executors\n * @see java.util.concurrent.CompletionService\n * @see java.util.concurrent.ExecutorCompletionService\n */\npublic final class TtlCallable<V> implements Callable<V>, TtlWrapper<Callable<V>>, TtlEnhanced, TtlAttachments {\n    private final AtomicReference<Capture> capturedRef;\n    private final Callable<V> callable;\n    private final boolean releaseTtlValueReferenceAfterCall;\n\n    private TtlCallable(@NonNull Callable<V> callable, boolean releaseTtlValueReferenceAfterCall) {\n        this.capturedRef = new AtomicReference<>(capture());\n        this.callable = callable;\n        this.releaseTtlValueReferenceAfterCall = releaseTtlValueReferenceAfterCall;\n    }\n\n    /**\n     * wrap method {@link Callable#call()}.\n     */\n    @Override\n    @SuppressFBWarnings(\"THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION\")\n    public V call() throws Exception {\n        final Capture captured = capturedRef.get();\n        if (captured == null || releaseTtlValueReferenceAfterCall && !capturedRef.compareAndSet(captured, null)) {\n            throw new IllegalStateException(\"TTL value reference is released after call!\");\n        }\n\n        final Backup backup = replay(captured);\n        try {\n            return callable.call();\n        } finally {\n            restore(backup);\n        }\n    }\n\n    /**\n     * return the original/underneath {@link Callable}.\n     */\n    @NonNull\n    public Callable<V> getCallable() {\n        return unwrap();\n    }\n\n    /**\n     * unwrap to the original/underneath {@link Callable}.\n     *\n     * @see TtlWrappers#unwrap(Object)\n     */\n    @NonNull\n    @Override\n    public Callable<V> unwrap() {\n        return callable;\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + callable.toString();\n    }\n\n    /**\n     * Factory method, wrap input {@link Callable} to {@link TtlCallable}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param callable input {@link Callable}\n     * @return Wrapped {@link Callable}\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T> TtlCallable<T> get(@Nullable Callable<T> callable) {\n        return get(callable, false, false);\n    }\n\n\n    /**\n     * Factory method, wrap input {@link Callable} to {@link TtlCallable}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param callable                          input {@link Callable}\n     * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @return Wrapped {@link Callable}\n     */\n    @Nullable\n    @Contract(value = \"null, _ -> null; !null, _ -> !null\", pure = true)\n    public static <T> TtlCallable<T> get(@Nullable Callable<T> callable, boolean releaseTtlValueReferenceAfterCall) {\n        return get(callable, releaseTtlValueReferenceAfterCall, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link Callable} to {@link TtlCallable}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param callable                          input {@link Callable}\n     * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @param idempotent                        is idempotent or not. {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return Wrapped {@link Callable}\n     */\n    @Nullable\n    @Contract(value = \"null, _, _ -> null; !null, _, _ -> !null\", pure = true)\n    public static <T> TtlCallable<T> get(@Nullable Callable<T> callable, boolean releaseTtlValueReferenceAfterCall, boolean idempotent) {\n        if (callable == null) return null;\n\n        if (callable instanceof TtlEnhanced) {\n            // avoid redundant decoration, and ensure idempotency\n            if (idempotent) return (TtlCallable<T>) callable;\n            else throw new IllegalStateException(\"Already TtlCallable!\");\n        }\n        return new TtlCallable<>(callable, releaseTtlValueReferenceAfterCall);\n    }\n\n    /**\n     * wrap input {@link Callable} Collection to {@link TtlCallable} Collection.\n     *\n     * @param tasks task to be wrapped\n     * @return Wrapped {@link Callable}\n     */\n    @NonNull\n    public static <T> List<TtlCallable<T>> gets(@Nullable Collection<? extends Callable<T>> tasks) {\n        return gets(tasks, false, false);\n    }\n\n    /**\n     * wrap input {@link Callable} Collection to {@link TtlCallable} Collection.\n     *\n     * @param tasks                             task to be wrapped\n     * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @return Wrapped {@link Callable}\n     */\n    @NonNull\n    public static <T> List<TtlCallable<T>> gets(@Nullable Collection<? extends Callable<T>> tasks, boolean releaseTtlValueReferenceAfterCall) {\n        return gets(tasks, releaseTtlValueReferenceAfterCall, false);\n    }\n\n    /**\n     * wrap input {@link Callable} Collection to {@link TtlCallable} Collection.\n     *\n     * @param tasks                             task to be wrapped\n     * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @param idempotent                        is idempotent or not. {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return Wrapped {@link Callable}\n     */\n    @NonNull\n    public static <T> List<TtlCallable<T>> gets(@Nullable Collection<? extends Callable<T>> tasks, boolean releaseTtlValueReferenceAfterCall, boolean idempotent) {\n        if (tasks == null) return Collections.emptyList();\n\n        List<TtlCallable<T>> copy = new ArrayList<>();\n        for (Callable<T> task : tasks) {\n            copy.add(TtlCallable.get(task, releaseTtlValueReferenceAfterCall, idempotent));\n        }\n        return copy;\n    }\n\n    /**\n     * Unwrap {@link TtlCallable} to the original/underneath one.\n     * <p>\n     * this method is {@code null}-safe, when input {@code Callable} parameter is {@code null}, return {@code null};\n     * if input {@code Callable} parameter is not a {@link TtlCallable} just return input {@code Callable}.\n     * <p>\n     * so {@code TtlCallable.unwrap(TtlCallable.get(callable))} will always return the same input {@code callable} object.\n     *\n     * @see #get(Callable)\n     * @see TtlWrappers#unwrap(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T> Callable<T> unwrap(@Nullable Callable<T> callable) {\n        if (!(callable instanceof TtlCallable)) return callable;\n        else return ((TtlCallable<T>) callable).getCallable();\n    }\n\n    /**\n     * Unwrap {@link TtlCallable} to the original/underneath one.\n     * <p>\n     * Invoke {@link #unwrap(Callable)} for each element in input collection.\n     * <p>\n     * This method is {@code null}-safe, when input {@code Callable} collection parameter is {@code null}, return an empty list.\n     *\n     * @see #gets(Collection)\n     * @see #unwrap(Callable)\n     */\n    @NonNull\n    public static <T> List<Callable<T>> unwraps(@Nullable Collection<? extends Callable<T>> tasks) {\n        if (tasks == null) return Collections.emptyList();\n\n        List<Callable<T>> copy = new ArrayList<>();\n        for (Callable<T> task : tasks) {\n            if (!(task instanceof TtlCallable)) copy.add(task);\n            else copy.add(((TtlCallable<T>) task).getCallable());\n        }\n        return copy;\n    }\n\n    private final TtlAttachmentsDelegate ttlAttachment = new TtlAttachmentsDelegate();\n\n    /**\n     * see {@link TtlAttachments#setTtlAttachment(String, Object)}\n     */\n    @Override\n    public void setTtlAttachment(@NonNull String key, Object value) {\n        ttlAttachment.setTtlAttachment(key, value);\n    }\n\n    /**\n     * see {@link TtlAttachments#getTtlAttachment(String)}\n     */\n    @Override\n    public <T> T getTtlAttachment(@NonNull String key) {\n        return ttlAttachment.getTtlAttachment(key);\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/TtlRecursiveAction.java",
    "content": "package com.alibaba.ttl3;\n\nimport com.alibaba.crr.composite.Backup;\nimport com.alibaba.crr.composite.Capture;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\n\nimport java.util.concurrent.ForkJoinTask;\n\nimport static com.alibaba.ttl3.transmitter.Transmitter.*;\n\n/**\n * A recursive resultless {@link ForkJoinTask} enhanced by {@link TransmittableThreadLocal}.\n * <p>\n * Recommend to use {@code  TTL Java Agent};\n * Specially for {@code Java 8} {@link java.util.stream.Stream} and {@link java.util.concurrent.CompletableFuture},\n * these async task are executed by {@link java.util.concurrent.ForkJoinPool} via {@link ForkJoinTask} at the bottom.\n *\n * @author LNAmp\n * @see java.util.concurrent.RecursiveAction\n * @see com.alibaba.ttl3.executor.TtlExecutors\n */\npublic abstract class TtlRecursiveAction extends ForkJoinTask<Void> implements TtlEnhanced {\n\n    private static final long serialVersionUID = -5753568484583412377L;\n\n    private final Capture captured = capture();\n\n    protected TtlRecursiveAction() {\n    }\n\n    /**\n     * The main computation performed by this task.\n     */\n    protected abstract void compute();\n\n    /**\n     * see {@link ForkJoinTask#getRawResult()}\n     */\n    public final Void getRawResult() {\n        return null;\n    }\n\n    /**\n     * see {@link ForkJoinTask#setRawResult(Object)}\n     */\n    protected final void setRawResult(Void mustBeNull) {\n    }\n\n    /**\n     * Implements execution conventions for RecursiveActions.\n     */\n    protected final boolean exec() {\n        final Backup backup = replay(captured);\n        try {\n            compute();\n            return true;\n        } finally {\n            restore(backup);\n        }\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/TtlRecursiveTask.java",
    "content": "package com.alibaba.ttl3;\n\nimport com.alibaba.crr.composite.Backup;\nimport com.alibaba.crr.composite.Capture;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\n\nimport java.util.concurrent.ForkJoinTask;\n\nimport static com.alibaba.ttl3.transmitter.Transmitter.*;\n\n/**\n * A recursive result-bearing {@link ForkJoinTask} enhanced by {@link TransmittableThreadLocal}.\n * <p>\n * Recommend to use {@code TTL Java Agent};\n * Specially for {@code Java 8} {@link java.util.stream.Stream} and {@link java.util.concurrent.CompletableFuture},\n * these async task are executed by {@link java.util.concurrent.ForkJoinPool} via {@link ForkJoinTask} at the bottom.\n *\n * @author LNAmp\n * @see java.util.concurrent.RecursiveTask\n * @see com.alibaba.ttl3.executor.TtlExecutors\n */\npublic abstract class TtlRecursiveTask<V> extends ForkJoinTask<V> implements TtlEnhanced {\n\n    private static final long serialVersionUID = 1814679366926362436L;\n\n    private final Capture captured = capture();\n\n    protected TtlRecursiveTask() {\n    }\n\n    /**\n     * The result of the computation.\n     */\n    V result;\n\n    /**\n     * The main computation performed by this task.\n     *\n     * @return the result of the computation\n     */\n    protected abstract V compute();\n\n    /**\n     * see {@link ForkJoinTask#getRawResult()}\n     */\n    public final V getRawResult() {\n        return result;\n    }\n\n    /**\n     * see {@link ForkJoinTask#setRawResult(Object)}\n     */\n    protected final void setRawResult(V value) {\n        result = value;\n    }\n\n    /**\n     * Implements execution conventions for RecursiveTask.\n     */\n    protected final boolean exec() {\n        final Backup backup = replay(captured);\n        try {\n            result = compute();\n            return true;\n        } finally {\n            restore(backup);\n        }\n    }\n\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/TtlRunnable.java",
    "content": "package com.alibaba.ttl3;\n\nimport com.alibaba.crr.composite.Backup;\nimport com.alibaba.crr.composite.Capture;\nimport com.alibaba.ttl3.spi.TtlAttachments;\nimport com.alibaba.ttl3.spi.TtlAttachmentsDelegate;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\nimport com.alibaba.ttl3.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static com.alibaba.ttl3.transmitter.Transmitter.*;\n\n/**\n * {@link TtlRunnable} decorate {@link Runnable} to get {@link TransmittableThreadLocal} value\n * and transmit it to the time of {@link Runnable} execution, needed when use {@link Runnable} to thread pool.\n * <p>\n * Use factory methods {@link #get} / {@link #gets} to create instance.\n * <p>\n * Other TTL Wrapper for common {@code Functional Interface} see {@link TtlWrappers}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.executor.TtlExecutors\n * @see TtlWrappers\n * @see java.util.concurrent.Executor\n * @see java.util.concurrent.ExecutorService\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ScheduledThreadPoolExecutor\n * @see java.util.concurrent.Executors\n */\npublic final class TtlRunnable implements Runnable, TtlWrapper<Runnable>, TtlEnhanced, TtlAttachments {\n    private final AtomicReference<Capture> capturedRef;\n    private final Runnable runnable;\n    private final boolean releaseTtlValueReferenceAfterRun;\n\n    private TtlRunnable(@NonNull Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {\n        this.capturedRef = new AtomicReference<>(capture());\n        this.runnable = runnable;\n        this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;\n    }\n\n    /**\n     * wrap method {@link Runnable#run()}.\n     */\n    @Override\n    public void run() {\n        final Capture captured = capturedRef.get();\n        if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {\n            throw new IllegalStateException(\"TTL value reference is released after run!\");\n        }\n\n        final Backup backup = replay(captured);\n        try {\n            runnable.run();\n        } finally {\n            restore(backup);\n        }\n    }\n\n    /**\n     * return original/unwrapped {@link Runnable}.\n     */\n    @NonNull\n    public Runnable getRunnable() {\n        return unwrap();\n    }\n\n    /**\n     * unwrap to original/unwrapped {@link Runnable}.\n     *\n     * @see TtlWrappers#unwrap(Object)\n     */\n    @NonNull\n    @Override\n    public Runnable unwrap() {\n        return runnable;\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + runnable.toString();\n    }\n\n    /**\n     * Factory method, wrap input {@link Runnable} to {@link TtlRunnable}.\n     *\n     * @param runnable input {@link Runnable}. if input is {@code null}, return {@code null}.\n     * @return Wrapped {@link Runnable}\n     * @throws IllegalStateException when input is {@link TtlRunnable} already.\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static TtlRunnable get(@Nullable Runnable runnable) {\n        return get(runnable, false, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link Runnable} to {@link TtlRunnable}.\n     *\n     * @param runnable                         input {@link Runnable}. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @return Wrapped {@link Runnable}\n     * @throws IllegalStateException when input is {@link TtlRunnable} already.\n     */\n    @Nullable\n    @Contract(value = \"null, _ -> null; !null, _ -> !null\", pure = true)\n    public static TtlRunnable get(@Nullable Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {\n        return get(runnable, releaseTtlValueReferenceAfterRun, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link Runnable} to {@link TtlRunnable}.\n     *\n     * @param runnable                         input {@link Runnable}. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @param idempotent                       is idempotent mode or not. if {@code true}, just return input {@link Runnable} when it's {@link TtlRunnable},\n     *                                         otherwise throw {@link IllegalStateException}.\n     *                                         <B><I>Caution</I></B>: {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return Wrapped {@link Runnable}\n     * @throws IllegalStateException when input is {@link TtlRunnable} already and not idempotent.\n     */\n    @Nullable\n    @Contract(value = \"null, _, _ -> null; !null, _, _ -> !null\", pure = true)\n    public static TtlRunnable get(@Nullable Runnable runnable, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {\n        if (runnable == null) return null;\n\n        if (runnable instanceof TtlEnhanced) {\n            // avoid redundant decoration, and ensure idempotency\n            if (idempotent) return (TtlRunnable) runnable;\n            else throw new IllegalStateException(\"Already TtlRunnable!\");\n        }\n        return new TtlRunnable(runnable, releaseTtlValueReferenceAfterRun);\n    }\n\n    /**\n     * wrap input {@link Runnable} Collection to {@link TtlRunnable} Collection.\n     *\n     * @param tasks task to be wrapped. if input is {@code null}, return {@code null}.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlRunnable} already.\n     */\n    @NonNull\n    public static List<TtlRunnable> gets(@Nullable Collection<? extends Runnable> tasks) {\n        return gets(tasks, false, false);\n    }\n\n    /**\n     * wrap input {@link Runnable} Collection to {@link TtlRunnable} Collection.\n     *\n     * @param tasks                            task to be wrapped. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlRunnable} already.\n     */\n    @NonNull\n    public static List<TtlRunnable> gets(@Nullable Collection<? extends Runnable> tasks, boolean releaseTtlValueReferenceAfterRun) {\n        return gets(tasks, releaseTtlValueReferenceAfterRun, false);\n    }\n\n    /**\n     * wrap input {@link Runnable} Collection to {@link TtlRunnable} Collection.\n     *\n     * @param tasks                            task to be wrapped. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @param idempotent                       is idempotent mode or not. if {@code true}, just return input {@link Runnable} when it's {@link TtlRunnable},\n     *                                         otherwise throw {@link IllegalStateException}.\n     *                                         <B><I>Caution</I></B>: {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlRunnable} already and not idempotent.\n     */\n    @NonNull\n    public static List<TtlRunnable> gets(@Nullable Collection<? extends Runnable> tasks, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {\n        if (tasks == null) return Collections.emptyList();\n\n        List<TtlRunnable> copy = new ArrayList<>();\n        for (Runnable task : tasks) {\n            copy.add(TtlRunnable.get(task, releaseTtlValueReferenceAfterRun, idempotent));\n        }\n        return copy;\n    }\n\n    /**\n     * Unwrap {@link TtlRunnable} to the original/underneath one.\n     * <p>\n     * this method is {@code null}-safe, when input {@code Runnable} parameter is {@code null}, return {@code null};\n     * if input {@code Runnable} parameter is not a {@link TtlRunnable} just return input {@code Runnable}.\n     * <p>\n     * so {@code TtlRunnable.unwrap(TtlRunnable.get(runnable))} will always return the same input {@code runnable} object.\n     *\n     * @see #get(Runnable)\n     * @see TtlWrappers#unwrap(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static Runnable unwrap(@Nullable Runnable runnable) {\n        if (!(runnable instanceof TtlRunnable)) return runnable;\n        else return ((TtlRunnable) runnable).getRunnable();\n    }\n\n    /**\n     * Unwrap {@link TtlRunnable} to the original/underneath one for collection.\n     * <p>\n     * Invoke {@link #unwrap(Runnable)} for each element in input collection.\n     * <p>\n     * This method is {@code null}-safe, when input {@code Runnable} parameter collection is {@code null}, return an empty list.\n     *\n     * @see #gets(Collection)\n     * @see #unwrap(Runnable)\n     */\n    @NonNull\n    public static List<Runnable> unwraps(@Nullable Collection<? extends Runnable> tasks) {\n        if (tasks == null) return Collections.emptyList();\n\n        List<Runnable> copy = new ArrayList<>();\n        for (Runnable task : tasks) {\n            if (!(task instanceof TtlRunnable)) copy.add(task);\n            else copy.add(((TtlRunnable) task).getRunnable());\n        }\n        return copy;\n    }\n\n    private final TtlAttachmentsDelegate ttlAttachment = new TtlAttachmentsDelegate();\n\n    /**\n     * see {@link TtlAttachments#setTtlAttachment(String, Object)}\n     */\n    @Override\n    public void setTtlAttachment(@NonNull String key, Object value) {\n        ttlAttachment.setTtlAttachment(key, value);\n    }\n\n    /**\n     * see {@link TtlAttachments#getTtlAttachment(String)}\n     */\n    @Override\n    public <T> T getTtlAttachment(@NonNull String key) {\n        return ttlAttachment.getTtlAttachment(key);\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/TtlTimerTask.java",
    "content": "package com.alibaba.ttl3;\n\nimport com.alibaba.crr.composite.Backup;\nimport com.alibaba.crr.composite.Capture;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\nimport com.alibaba.ttl3.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.*;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static com.alibaba.ttl3.transmitter.Transmitter.*;\n\n/**\n * {@link TtlTimerTask} decorate {@link TimerTask} to get {@link TransmittableThreadLocal} value\n * and transmit it to the time of {@link TtlTimerTask} execution, needed when use {@link TtlTimerTask} to {@link TimerTask}.\n * <p>\n * Use factory method {@link #get(TimerTask)} to create instance.\n * <p>\n * <B><I>CAUTION:</I></B><br>\n * The {@link TtlTimerTask} make the method {@link TimerTask#scheduledExecutionTime()} in\n * the origin {@link TimerTask} lose effectiveness! Use {@code TTL Java Agent} instead.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see Timer\n * @see TimerTask\n * @see <a href=\"https://alibaba.github.io/Alibaba-Java-Coding-Guidelines/#concurrency\">\n * Alibaba Java Coding Guidelines - Concurrency -\n * Item 10: [Mandatory] Run multiple TimeTask by using ScheduledExecutorService\n * rather than Timer because Timer will kill all running threads\n * in case of failing to catch exceptions.</a>\n * @deprecated Use {@link TtlRunnable}, {@link java.util.concurrent.ScheduledExecutorService}\n * instead of {@link Timer}, {@link TimerTask}.\n */\n@Deprecated\npublic final class TtlTimerTask extends TimerTask implements TtlWrapper<TimerTask>, TtlEnhanced {\n    private final AtomicReference<Capture> capturedRef;\n    private final TimerTask timerTask;\n    private final boolean releaseTtlValueReferenceAfterRun;\n\n    private TtlTimerTask(@NonNull TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun) {\n        this.capturedRef = new AtomicReference<>(capture());\n        this.timerTask = timerTask;\n        this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;\n    }\n\n    /**\n     * wrap method {@link TimerTask#run()}.\n     */\n    @Override\n    public void run() {\n        final Capture captured = capturedRef.get();\n        if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {\n            throw new IllegalStateException(\"TTL value reference is released after run!\");\n        }\n\n        final Backup backup = replay(captured);\n        try {\n            timerTask.run();\n        } finally {\n            restore(backup);\n        }\n    }\n\n    @Override\n    public boolean cancel() {\n        timerTask.cancel();\n        return super.cancel();\n    }\n\n    /**\n     * return original/unwrapped {@link TimerTask}.\n     */\n    @NonNull\n    public TimerTask getTimerTask() {\n        return unwrap();\n    }\n\n    /**\n     * unwrap to original/unwrapped {@link TimerTask}.\n     *\n     * @see TtlWrappers#unwrap(Object)\n     */\n    @NonNull\n    @Override\n    public TimerTask unwrap() {\n        return timerTask;\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + timerTask.toString();\n    }\n\n    /**\n     * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param timerTask input {@link TimerTask}\n     * @return Wrapped {@link TimerTask}\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static TtlTimerTask get(@Nullable TimerTask timerTask) {\n        return get(timerTask, false, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param timerTask                        input {@link TimerTask}\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlTimerTask} is referred.\n     * @return Wrapped {@link TimerTask}\n     */\n    @Nullable\n    @Contract(value = \"null, _ -> null; !null, _ -> !null\", pure = true)\n    public static TtlTimerTask get(@Nullable TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun) {\n        return get(timerTask, releaseTtlValueReferenceAfterRun, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param timerTask                        input {@link TimerTask}\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlTimerTask} is referred.\n     * @param idempotent                       is idempotent or not. {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return Wrapped {@link TimerTask}\n     */\n    @Nullable\n    @Contract(value = \"null, _, _ -> null; !null, _, _ -> !null\", pure = true)\n    public static TtlTimerTask get(@Nullable TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {\n        if (timerTask == null) return null;\n\n        if (timerTask instanceof TtlEnhanced) {\n            // avoid redundant decoration, and ensure idempotency\n            if (idempotent) return (TtlTimerTask) timerTask;\n            else throw new IllegalStateException(\"Already TtlTimerTask!\");\n        }\n        return new TtlTimerTask(timerTask, releaseTtlValueReferenceAfterRun);\n    }\n\n    /**\n     * Unwrap {@link TtlTimerTask} to the original/underneath one.\n     * <p>\n     * this method is {@code null}-safe, when input {@code TimerTask} parameter is {@code null}, return {@code null};\n     * if input {@code TimerTask} parameter is not a {@link TtlTimerTask} just return input {@code TimerTask}.\n     *\n     * @see #get(TimerTask)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static TimerTask unwrap(@Nullable TimerTask timerTask) {\n        if (!(timerTask instanceof TtlTimerTask)) return timerTask;\n        else return ((TtlTimerTask) timerTask).getTimerTask();\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/TtlWrappers.java",
    "content": "package com.alibaba.ttl3;\n\nimport com.alibaba.crr.composite.Backup;\nimport com.alibaba.crr.composite.Capture;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\nimport com.alibaba.ttl3.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.function.*;\n\nimport static com.alibaba.ttl3.transmitter.Transmitter.*;\n\n/**\n * Util methods for TTL Wrapper.\n *\n * <ul>\n * <li>wrap common {@code Functional Interface}.<br>\n *     if missing your desired wrapper util method,\n *     you need implement your own util method alike.\n * </li>\n * <li>unwrap TTL Wrapper and check whether it is TTL Wrapper.</li>\n * </ul>\n * <p>\n * <b><i>Note:</i></b>\n * <ul>\n * <li>all methods is {@code null}-safe, when input parameter is {@code null}, return {@code null}.</li>\n * <li>all wrap method skip wrapping (aka. just return input parameter), when input parameter is already wrapped.</li>\n * <li>the wrap methods for {@link Runnable} and {@link java.util.concurrent.Callable Callable} are provided\n *     by {@link TtlRunnable#get(Runnable)} and {@link TtlCallable#get(java.util.concurrent.Callable) TtlCallable.get(Callable)}.</li>\n * <li>the wrap methods for {@link java.util.concurrent.Executor Executor} are provided\n *     by {@link com.alibaba.ttl3.executor.TtlExecutors TtlExecutors}.</li>\n * </ul>\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author huangfei1101 (fei.hf at alibaba-inc dot com)\n * @see TtlRunnable\n * @see TtlCallable\n * @see TtlWrapper\n * @see com.alibaba.ttl3.executor.TtlExecutors TtlExecutors\n */\npublic final class TtlWrappers {\n    /**\n     * wrap {@link Supplier} to TTL wrapper.\n     *\n     * @param supplier input {@link Supplier}\n     * @return Wrapped {@link Supplier}\n     * @see TtlWrappers#unwrap(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T> Supplier<T> wrapSupplier(@Nullable Supplier<T> supplier) {\n        if (supplier == null) return null;\n        else if (supplier instanceof TtlEnhanced) return supplier;\n        else return new TtlSupplier<>(supplier);\n    }\n\n    /**\n     * wrap {@link Consumer} to TTL wrapper.\n     *\n     * @param consumer input {@link Consumer}\n     * @return Wrapped {@link Consumer}\n     * @see TtlWrappers#unwrap(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T> Consumer<T> wrapConsumer(@Nullable Consumer<T> consumer) {\n        if (consumer == null) return null;\n        else if (consumer instanceof TtlEnhanced) return consumer;\n        else return new TtlConsumer<>(consumer);\n    }\n\n    /**\n     * wrap {@link BiConsumer} to TTL wrapper.\n     *\n     * @param consumer input {@link BiConsumer}\n     * @return Wrapped {@link BiConsumer}\n     * @see TtlWrappers#unwrap(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T, U> BiConsumer<T, U> wrapBiConsumer(@Nullable BiConsumer<T, U> consumer) {\n        if (consumer == null) return null;\n        else if (consumer instanceof TtlEnhanced) return consumer;\n        else return new TtlBiConsumer<>(consumer);\n    }\n\n    /**\n     * wrap {@link Function} to TTL wrapper.\n     *\n     * @param fn input {@link Function}\n     * @return Wrapped {@link Function}\n     * @see TtlWrappers#unwrap(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T, R> Function<T, R> wrapFunction(@Nullable Function<T, R> fn) {\n        if (fn == null) return null;\n        else if (fn instanceof TtlEnhanced) return fn;\n        else return new TtlFunction<>(fn);\n    }\n\n    /**\n     * wrap {@link BiFunction} to TTL wrapper.\n     *\n     * @param fn input {@link BiFunction}\n     * @return Wrapped {@link BiFunction}\n     * @see TtlWrappers#unwrap(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T, U, R> BiFunction<T, U, R> wrapBiFunction(@Nullable BiFunction<T, U, R> fn) {\n        if (fn == null) return null;\n        else if (fn instanceof TtlEnhanced) return fn;\n        else return new TtlBiFunction<>(fn);\n    }\n\n    /**\n     * Generic unwrap method, unwrap {@link TtlWrapper} to the original/underneath one.\n     * <p>\n     * this method is {@code null}-safe, when input parameter is {@code null}, return {@code null};\n     * if input parameter is not a {@link TtlWrapper} just return input.\n     *\n     * @see TtlWrappers#wrapSupplier(Supplier)\n     * @see TtlWrappers#wrapConsumer(Consumer)\n     * @see TtlWrappers#wrapBiConsumer(BiConsumer)\n     * @see TtlWrappers#wrapFunction(Function)\n     * @see TtlWrappers#wrapBiFunction(BiFunction)\n     * @see TtlRunnable#get(Runnable)\n     * @see TtlCallable#get(java.util.concurrent.Callable) TtlCallable.get(Callable)\n     * @see com.alibaba.ttl3.executor.TtlExecutors#getTtlExecutor(java.util.concurrent.Executor) TtlExecutors.getTtlExecutor(Executor)\n     * @see com.alibaba.ttl3.executor.TtlExecutors#getTtlExecutorService(java.util.concurrent.ExecutorService) TtlExecutors.getTtlExecutorService(ExecutorService)\n     * @see com.alibaba.ttl3.executor.TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory) TtlExecutors.getDisableInheritableThreadFactory(ThreadFactory)\n     * @see com.alibaba.ttl3.executor.TtlExecutors#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory) TtlExecutors.getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory)\n     * @see TtlRunnable#unwrap(Runnable)\n     * @see TtlCallable#unwrap(java.util.concurrent.Callable) TtlCallable.unwrap(Callable)\n     * @see com.alibaba.ttl3.executor.TtlExecutors#unwrapTtlExecutor(java.util.concurrent.Executor) TtlExecutors.unwrapTtlExecutor(Executor)\n     * @see com.alibaba.ttl3.executor.TtlExecutors#unwrapDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory) TtlExecutors.unwrapDisableInheritableThreadFactory(ThreadFactory)\n     * @see com.alibaba.ttl3.executor.TtlExecutors#unwrapDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory) TtlExecutors.unwrapDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory)\n     * @see com.alibaba.ttl3.executor.TtlExecutors#unwrapTtlRunnableUnwrapComparator(java.util.Comparator) TtlExecutors.unwrapTtlRunnableUnwrapComparator(Comparator)\n     * @see #isWrapper(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T unwrap(@Nullable T obj) {\n        if (!isWrapper(obj)) return obj;\n        else return ((TtlWrapper<T>) obj).unwrap();\n    }\n\n    /**\n     * check the input object is a {@code TtlWrapper} or not.\n     *\n     * @see #unwrap(Object)\n     */\n    public static <T> boolean isWrapper(@Nullable T obj) {\n        return obj instanceof TtlWrapper;\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    // private inner classes\n    ///////////////////////////////////////////////////////////////////////////\n\n    private static class TtlSupplier<T> implements Supplier<T>, TtlWrapper<Supplier<T>>, TtlEnhanced {\n        final Supplier<T> supplier;\n        final Capture captured;\n\n        TtlSupplier(@NonNull Supplier<T> supplier) {\n            this.supplier = supplier;\n            this.captured = capture();\n        }\n\n        @Override\n        public T get() {\n            final Backup backup = replay(captured);\n            try {\n                return supplier.get();\n            } finally {\n                restore(backup);\n            }\n        }\n\n        @NonNull\n        @Override\n        public Supplier<T> unwrap() {\n            return supplier;\n        }\n\n        @Override\n        public String toString() {\n            return this.getClass().getName() + \" - \" + supplier.toString();\n        }\n    }\n\n    private static class TtlConsumer<T> implements Consumer<T>, TtlWrapper<Consumer<T>>, TtlEnhanced {\n        final Consumer<T> consumer;\n        final Capture captured;\n\n        TtlConsumer(@NonNull Consumer<T> consumer) {\n            this.consumer = consumer;\n            this.captured = capture();\n        }\n\n        @Override\n        public void accept(T t) {\n            final Backup backup = replay(captured);\n            try {\n                consumer.accept(t);\n            } finally {\n                restore(backup);\n            }\n        }\n\n        @NonNull\n        @Override\n        public Consumer<T> unwrap() {\n            return consumer;\n        }\n\n        @Override\n        public String toString() {\n            return this.getClass().getName() + \" - \" + consumer.toString();\n        }\n    }\n\n    private static class TtlBiConsumer<T, U> implements BiConsumer<T, U>, TtlWrapper<BiConsumer<T, U>>, TtlEnhanced {\n        final BiConsumer<T, U> consumer;\n        final Capture captured;\n\n        TtlBiConsumer(@NonNull BiConsumer<T, U> consumer) {\n            this.consumer = consumer;\n            this.captured = capture();\n        }\n\n        @Override\n        public void accept(T t, U u) {\n            final Backup backup = replay(captured);\n            try {\n                consumer.accept(t, u);\n            } finally {\n                restore(backup);\n            }\n        }\n\n        @NonNull\n        @Override\n        public BiConsumer<T, U> unwrap() {\n            return consumer;\n        }\n\n        @Override\n        public String toString() {\n            return this.getClass().getName() + \" - \" + consumer.toString();\n        }\n    }\n\n    private static class TtlFunction<T, R> implements Function<T, R>, TtlWrapper<Function<T, R>>, TtlEnhanced {\n        final Function<T, R> fn;\n        final Capture captured;\n\n        TtlFunction(@NonNull Function<T, R> fn) {\n            this.fn = fn;\n            this.captured = capture();\n        }\n\n        @Override\n        public R apply(T t) {\n            final Backup backup = replay(captured);\n            try {\n                return fn.apply(t);\n            } finally {\n                restore(backup);\n            }\n        }\n\n        @NonNull\n        @Override\n        public Function<T, R> unwrap() {\n            return fn;\n        }\n\n        @Override\n        public String toString() {\n            return this.getClass().getName() + \" - \" + fn.toString();\n        }\n    }\n\n    private static class TtlBiFunction<T, U, R> implements BiFunction<T, U, R>, TtlWrapper<BiFunction<T, U, R>>, TtlEnhanced {\n        final BiFunction<T, U, R> fn;\n        final Capture captured;\n\n        TtlBiFunction(@NonNull BiFunction<T, U, R> fn) {\n            this.fn = fn;\n            this.captured = capture();\n        }\n\n        @Override\n        public R apply(T t, U u) {\n            final Backup backup = replay(captured);\n            try {\n                return fn.apply(t, u);\n            } finally {\n                restore(backup);\n            }\n        }\n\n        @NonNull\n        @Override\n        public BiFunction<T, U, R> unwrap() {\n            return fn;\n        }\n\n        @Override\n        public String toString() {\n            return this.getClass().getName() + \" - \" + fn.toString();\n        }\n    }\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlWrappers() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/agent/EmptyTtlAgentStatus.java",
    "content": "package com.alibaba.ttl3.agent;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport static com.alibaba.ttl3.internal.util.Utils.propagateIfFatal;\n\nfinal class EmptyTtlAgentStatus implements TtlAgentStatus {\n    @Override\n    public boolean isTtlAgentLoaded() {\n        return false;\n    }\n\n    private EmptyTtlAgentStatus() {\n    }\n\n\n    ///////////////////////////////////////////////////////////////////////////\n    // Singleton maintenance logic\n    ///////////////////////////////////////////////////////////////////////////\n\n    private static volatile TtlAgentStatus ttlAgentStatus = null;\n\n    @NonNull\n    static TtlAgentStatus getLoadedAgentOrEmpty() {\n        if (ttlAgentStatus != null) return ttlAgentStatus;\n\n        synchronized (EmptyTtlAgentStatus.class) {\n            // double check\n            if (ttlAgentStatus != null) return ttlAgentStatus;\n\n            final String TTL_AGENT_CLASS = \"com.alibaba.ttl3.agent.TtlAgent\";\n\n            TtlAgentStatus ret;\n            try {\n                ret = (TtlAgentStatus) Class.forName(TTL_AGENT_CLASS).getDeclaredConstructor().newInstance();\n            } catch (ClassNotFoundException e) {\n                ret = new EmptyTtlAgentStatus();\n            } catch (Exception e) {\n                propagateIfFatal(e);\n                throw new IllegalStateException(\"Fail to create the TTL agent instance(\" + TTL_AGENT_CLASS\n                        + \"), should be a bug! report to the TTL project. cause: \" + e, e);\n            }\n\n            ttlAgentStatus = ret;\n            return ret;\n        }\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/agent/TtlAgentStatus.java",
    "content": "package com.alibaba.ttl3.agent;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport static com.alibaba.ttl3.agent.EmptyTtlAgentStatus.getLoadedAgentOrEmpty;\n\npublic interface TtlAgentStatus {\n    /**\n     * Whether TTL agent is loaded.\n     */\n    boolean isTtlAgentLoaded();\n\n    @NonNull\n    static TtlAgentStatus getInstance() {\n        return getLoadedAgentOrEmpty();\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/agent/package-info.java",
    "content": "/**\n * Provide {@link com.alibaba.ttl3.agent.TtlAgentStatus}\n * to get {@code TTL Agent status}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.agent.TtlAgentStatus\n */\npackage com.alibaba.ttl3.agent;\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/executor/ComparableComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.ttl3.executor;\n\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This source code file is copied and small adopted from commons-collections4 4.4:\n//\n// https://github.com/apache/commons-collections/blob/commons-commons-collections-4.4/src/main/java/org/apache/commons/collections4/comparators/ComparableComparator.java\n//\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\nimport java.io.Serializable;\nimport java.util.Comparator;\n\n/**\n * A {@link Comparator Comparator} that compares {@link Comparable Comparable}\n * objects.\n * <p>\n * This Comparator is useful, for example, for enforcing the natural order in\n * custom implementations of {@link java.util.SortedSet SortedSet} and\n * {@link java.util.SortedMap SortedMap}.\n * </p>\n * <p>\n * Note: In the 2.0 and 2.1 releases of Commons Collections, this class would\n * throw a {@link ClassCastException} if either of the arguments to\n * {@link #compare compare} were <code>null</code>, not\n * {@link Comparable Comparable}, or for which\n * {@link Comparable#compareTo(Object) compareTo} gave inconsistent results.\n * This is no longer the case. See {@link #compare compare} for\n * details.\n * </p>\n *\n * @param <E> the type of objects compared by this comparator\n *\n * @see java.util.Collections#reverseOrder()\n */\nfinal class ComparableComparator<E extends Comparable<? super E>> implements Comparator<E>, Serializable {\n\n    /** Serialization version. */\n    private static final long serialVersionUID=-291439688585137865L;\n\n    /** The singleton instance. */\n    @SuppressWarnings(\"rawtypes\")\n    public static final ComparableComparator INSTANCE = new ComparableComparator();\n\n    //-----------------------------------------------------------------------\n    /**\n     * Gets the singleton instance of a ComparableComparator.\n     * <p>\n     * Developers are encouraged to use the comparator returned from this method\n     * instead of constructing a new instance to reduce allocation and GC overhead\n     * when multiple comparable comparators may be used in the same VM.\n     *\n     * @param <E>  the element type\n     * @return the singleton ComparableComparator\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <E extends Comparable<? super E>> ComparableComparator<E> comparableComparator() {\n        return INSTANCE;\n    }\n\n    //-----------------------------------------------------------------------\n    /**\n     * Constructor whose use should be avoided.\n     * <p>\n     * Please use the {@link #comparableComparator()} method whenever possible.\n     */\n    public ComparableComparator() {\n        super();\n    }\n\n    //-----------------------------------------------------------------------\n    /**\n     * Compare the two {@link Comparable Comparable} arguments.\n     * This method is equivalent to:\n     * <pre>((Comparable)obj1).compareTo(obj2)</pre>\n     *\n     * @param obj1  the first object to compare\n     * @param obj2  the second object to compare\n     * @return negative if obj1 is less, positive if greater, zero if equal\n     * @throws NullPointerException if <i>obj1</i> is <code>null</code>,\n     *         or when <code>((Comparable)obj1).compareTo(obj2)</code> does\n     * @throws ClassCastException if <i>obj1</i> is not a <code>Comparable</code>,\n     *         or when <code>((Comparable)obj1).compareTo(obj2)</code> does\n     */\n    @Override\n    public int compare(final E obj1, final E obj2) {\n        return obj1.compareTo(obj2);\n    }\n\n    //-----------------------------------------------------------------------\n    /**\n     * Implement a hash code for this comparator that is consistent with\n     * {@link #equals(Object) equals}.\n     *\n     * @return a hash code for this comparator.\n     */\n    @Override\n    public int hashCode() {\n        return \"ComparableComparator\".hashCode();\n    }\n\n    /**\n     * Returns {@code true} iff <i>that</i> Object is a {@link Comparator Comparator}\n     * whose ordering is known to be equivalent to mine.\n     * <p>\n     * This implementation returns {@code true} iff\n     * <code><i>object</i>.{@link Object#getClass() getClass()}</code> equals\n     * <code>this.getClass()</code>. Subclasses may want to override this behavior to remain\n     * consistent with the {@link Comparator#equals(Object)} contract.\n     *\n     * @param object  the object to compare with\n     * @return {@code true} if equal\n     */\n    @Override\n    public boolean equals(final Object object) {\n        return this == object ||\n               null != object && object.getClass().equals(this.getClass());\n    }\n\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/executor/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java",
    "content": "package com.alibaba.ttl3.executor;\n\nimport com.alibaba.crr.composite.Backup;\nimport com.alibaba.ttl3.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;\nimport java.util.concurrent.ForkJoinWorkerThread;\n\nimport static com.alibaba.ttl3.transmitter.Transmitter.clear;\nimport static com.alibaba.ttl3.transmitter.Transmitter.restore;\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfinal class DisableInheritableForkJoinWorkerThreadFactoryWrapper implements ForkJoinWorkerThreadFactory, TtlWrapper<ForkJoinWorkerThreadFactory> {\n    private final ForkJoinWorkerThreadFactory threadFactory;\n\n    DisableInheritableForkJoinWorkerThreadFactoryWrapper(@NonNull ForkJoinWorkerThreadFactory threadFactory) {\n        this.threadFactory = threadFactory;\n    }\n\n    @Override\n    public ForkJoinWorkerThread newThread(ForkJoinPool pool) {\n        final Backup backup = clear();\n        try {\n            return threadFactory.newThread(pool);\n        } finally {\n            restore(backup);\n        }\n    }\n\n    @Override\n    @NonNull\n    public ForkJoinWorkerThreadFactory unwrap() {\n        return threadFactory;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        DisableInheritableForkJoinWorkerThreadFactoryWrapper that = (DisableInheritableForkJoinWorkerThreadFactoryWrapper) o;\n\n        return threadFactory.equals(that.threadFactory);\n    }\n\n    @Override\n    public int hashCode() {\n        return threadFactory.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + threadFactory;\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/executor/DisableInheritableThreadFactoryWrapper.java",
    "content": "package com.alibaba.ttl3.executor;\n\nimport com.alibaba.crr.composite.Backup;\nimport com.alibaba.ttl3.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.concurrent.ThreadFactory;\n\nimport static com.alibaba.ttl3.transmitter.Transmitter.clear;\nimport static com.alibaba.ttl3.transmitter.Transmitter.restore;\n\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfinal class DisableInheritableThreadFactoryWrapper implements ThreadFactory, TtlWrapper<ThreadFactory> {\n    private final ThreadFactory threadFactory;\n\n    DisableInheritableThreadFactoryWrapper(@NonNull ThreadFactory threadFactory) {\n        this.threadFactory = threadFactory;\n    }\n\n    @Override\n    public Thread newThread(@NonNull Runnable r) {\n        final Backup backup = clear();\n        try {\n            return threadFactory.newThread(r);\n        } finally {\n            restore(backup);\n        }\n    }\n\n    @NonNull\n    @Override\n    public ThreadFactory unwrap() {\n        return threadFactory;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        DisableInheritableThreadFactoryWrapper that = (DisableInheritableThreadFactoryWrapper) o;\n\n        return threadFactory.equals(that.threadFactory);\n    }\n\n    @Override\n    public int hashCode() {\n        return threadFactory.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + threadFactory;\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/executor/ExecutorServiceTtlWrapper.java",
    "content": "package com.alibaba.ttl3.executor;\n\nimport com.alibaba.ttl3.TransmittableThreadLocal;\nimport com.alibaba.ttl3.TtlCallable;\nimport com.alibaba.ttl3.TtlRunnable;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.*;\n\n/**\n * {@link TransmittableThreadLocal} Wrapper of {@link ExecutorService},\n * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link Callable}\n * to the execution time of {@link Runnable} or {@link Callable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\n@SuppressFBWarnings({\"EQ_DOESNT_OVERRIDE_EQUALS\"})\nclass ExecutorServiceTtlWrapper extends ExecutorTtlWrapper implements ExecutorService, TtlEnhanced {\n    private final ExecutorService executorService;\n\n    ExecutorServiceTtlWrapper(@NonNull ExecutorService executorService, boolean idempotent) {\n        super(executorService, idempotent);\n        this.executorService = executorService;\n    }\n\n    @Override\n    public void shutdown() {\n        executorService.shutdown();\n    }\n\n    @NonNull\n    @Override\n    public List<Runnable> shutdownNow() {\n        return executorService.shutdownNow();\n    }\n\n    @Override\n    public boolean isShutdown() {\n        return executorService.isShutdown();\n    }\n\n    @Override\n    public boolean isTerminated() {\n        return executorService.isTerminated();\n    }\n\n    @Override\n    public boolean awaitTermination(long timeout, @NonNull TimeUnit unit) throws InterruptedException {\n        return executorService.awaitTermination(timeout, unit);\n    }\n\n    @NonNull\n    @Override\n    public <T> Future<T> submit(@NonNull Callable<T> task) {\n        return executorService.submit(TtlCallable.get(task, false, idempotent));\n    }\n\n    @NonNull\n    @Override\n    public <T> Future<T> submit(@NonNull Runnable task, T result) {\n        return executorService.submit(TtlRunnable.get(task, false, idempotent), result);\n    }\n\n    @NonNull\n    @Override\n    public Future<?> submit(@NonNull Runnable task) {\n        return executorService.submit(TtlRunnable.get(task, false, idempotent));\n    }\n\n    @NonNull\n    @Override\n    public <T> List<Future<T>> invokeAll(@NonNull Collection<? extends Callable<T>> tasks) throws InterruptedException {\n        return executorService.invokeAll(TtlCallable.gets(tasks, false, idempotent));\n    }\n\n    @NonNull\n    @Override\n    public <T> List<Future<T>> invokeAll(@NonNull Collection<? extends Callable<T>> tasks, long timeout, @NonNull TimeUnit unit) throws InterruptedException {\n        return executorService.invokeAll(TtlCallable.gets(tasks, false, idempotent), timeout, unit);\n    }\n\n    @NonNull\n    @Override\n    public <T> T invokeAny(@NonNull Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {\n        return executorService.invokeAny(TtlCallable.gets(tasks, false, idempotent));\n    }\n\n    @Override\n    public <T> T invokeAny(@NonNull Collection<? extends Callable<T>> tasks, long timeout, @NonNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {\n        return executorService.invokeAny(TtlCallable.gets(tasks, false, idempotent), timeout, unit);\n    }\n\n    @NonNull\n    @Override\n    public ExecutorService unwrap() {\n        return executorService;\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/executor/ExecutorTtlWrapper.java",
    "content": "package com.alibaba.ttl3.executor;\n\nimport com.alibaba.ttl3.TransmittableThreadLocal;\nimport com.alibaba.ttl3.TtlRunnable;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\nimport com.alibaba.ttl3.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.concurrent.Executor;\n\n/**\n * {@link TransmittableThreadLocal} Wrapper of {@link Executor},\n * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable}\n * to the execution time of {@link Runnable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass ExecutorTtlWrapper implements Executor, TtlWrapper<Executor>, TtlEnhanced {\n    private final Executor executor;\n    protected final boolean idempotent;\n\n    ExecutorTtlWrapper(@NonNull Executor executor, boolean idempotent) {\n        this.executor = executor;\n        this.idempotent = idempotent;\n    }\n\n    @Override\n    public void execute(@NonNull Runnable command) {\n        executor.execute(TtlRunnable.get(command, false, idempotent));\n    }\n\n    @NonNull\n    @Override\n    public Executor unwrap() {\n        return executor;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        ExecutorTtlWrapper that = (ExecutorTtlWrapper) o;\n\n        if (idempotent != that.idempotent) return false;\n        return executor.equals(that.executor);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = executor.hashCode();\n        result = 31 * result + (idempotent ? 1 : 0);\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + executor;\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/executor/ScheduledExecutorServiceTtlWrapper.java",
    "content": "package com.alibaba.ttl3.executor;\n\nimport com.alibaba.ttl3.TransmittableThreadLocal;\nimport com.alibaba.ttl3.TtlCallable;\nimport com.alibaba.ttl3.TtlRunnable;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * {@link TransmittableThreadLocal} Wrapper of {@link ScheduledExecutorService},\n * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link Callable}\n * to the execution time of {@link Runnable} or {@link Callable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\n@SuppressFBWarnings({\"EQ_DOESNT_OVERRIDE_EQUALS\"})\nclass ScheduledExecutorServiceTtlWrapper extends ExecutorServiceTtlWrapper implements ScheduledExecutorService, TtlEnhanced {\n    final ScheduledExecutorService scheduledExecutorService;\n\n    public ScheduledExecutorServiceTtlWrapper(@NonNull ScheduledExecutorService scheduledExecutorService, boolean idempotent) {\n        super(scheduledExecutorService, idempotent);\n        this.scheduledExecutorService = scheduledExecutorService;\n    }\n\n    @NonNull\n    @Override\n    public ScheduledFuture<?> schedule(@NonNull Runnable command, long delay, @NonNull TimeUnit unit) {\n        return scheduledExecutorService.schedule(TtlRunnable.get(command, false, idempotent), delay, unit);\n    }\n\n    @NonNull\n    @Override\n    public <V> ScheduledFuture<V> schedule(@NonNull Callable<V> callable, long delay, @NonNull TimeUnit unit) {\n        return scheduledExecutorService.schedule(TtlCallable.get(callable, false, idempotent), delay, unit);\n    }\n\n    @NonNull\n    @Override\n    public ScheduledFuture<?> scheduleAtFixedRate(@NonNull Runnable command, long initialDelay, long period, @NonNull TimeUnit unit) {\n        return scheduledExecutorService.scheduleAtFixedRate(TtlRunnable.get(command, false, idempotent), initialDelay, period, unit);\n    }\n\n    @NonNull\n    @Override\n    public ScheduledFuture<?> scheduleWithFixedDelay(@NonNull Runnable command, long initialDelay, long delay, @NonNull TimeUnit unit) {\n        return scheduledExecutorService.scheduleWithFixedDelay(TtlRunnable.get(command, false, idempotent), initialDelay, delay, unit);\n    }\n\n    @NonNull\n    @Override\n    public ScheduledExecutorService unwrap() {\n        return scheduledExecutorService;\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/executor/TtlExecutors.java",
    "content": "package com.alibaba.ttl3.executor;\n\nimport com.alibaba.ttl3.TransmittableThreadLocal;\nimport com.alibaba.ttl3.agent.TtlAgentStatus;\nimport com.alibaba.ttl3.spi.TtlEnhanced;\nimport com.alibaba.ttl3.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.Comparator;\nimport java.util.concurrent.*;\nimport java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;\n\n/**\n * Util methods for TTL wrapper of jdk executors.\n *\n * <ol>\n *     <li>wrap/check/unwrap methods for TTL wrapper of\n *         jdk executors({@link Executor}, {@link ExecutorService}, {@link ScheduledExecutorService}).</li>\n *     <li>wrap/check/unwrap methods for disable Inheritable wrapper of {@link ThreadFactory}.</li>\n *     <li>wrap/check/unwrap methods for disable Inheritable wrapper of {@link ForkJoinWorkerThreadFactory}.</li>\n *     <li>wrap/check/unwrap methods for {@code TtlRunnableUnwrapComparator} wrapper of {@link PriorityBlockingQueue}\n *         for {@link ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue)}.</li>\n * </ol>\n * <p>\n * <b><i>Note:</i></b>\n * <ul>\n * <li>all method is {@code null}-safe.\n *     for wrap/unwrap methods when input parameter is {@code null}, return {@code null}.\n *     for check methods when input parameter is {@code null}, return {@code false}.</li>\n * <li>skip wrap/decoration thread pool/{@code executor}(aka. just return input {@code executor})\n *     when ttl agent is loaded, Or when input {@code executor} is already wrapped/decorated.</li>\n * </ul>\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see Executor\n * @see ExecutorService\n * @see ScheduledExecutorService\n * @see ThreadPoolExecutor\n * @see ScheduledThreadPoolExecutor\n * @see Executors\n * @see ThreadFactory\n * @see Executors#defaultThreadFactory()\n * @see ForkJoinPool\n * @see ForkJoinWorkerThreadFactory\n * @see ForkJoinPool#defaultForkJoinWorkerThreadFactory\n * @see ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue)\n * @see PriorityBlockingQueue\n */\npublic final class TtlExecutors {\n\n    ///////////////////////////////////////////////////////////////////////////\n    // Executor utils\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * {@link TransmittableThreadLocal} Wrapper of {@link Executor},\n     * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable}\n     * to the execution time of {@link Runnable}.\n     *\n     * @param executor input Executor\n     * @return wrapped Executor\n     * @see com.alibaba.ttl3.TtlRunnable#get(Runnable, boolean, boolean)\n     * @see com.alibaba.ttl3.TtlCallable#get(Callable, boolean, boolean)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static Executor getTtlExecutor(@Nullable Executor executor) {\n        if (TtlAgentStatus.getInstance().isTtlAgentLoaded() || executor == null || executor instanceof TtlEnhanced) {\n            return executor;\n        }\n        return new ExecutorTtlWrapper(executor, true);\n    }\n\n    /**\n     * {@link TransmittableThreadLocal} Wrapper of {@link ExecutorService},\n     * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link Callable}\n     * to the execution time of {@link Runnable} or {@link Callable}.\n     *\n     * @param executorService input ExecutorService\n     * @return wrapped ExecutorService\n     * @see com.alibaba.ttl3.TtlRunnable#get(Runnable, boolean, boolean)\n     * @see com.alibaba.ttl3.TtlCallable#get(Callable, boolean, boolean)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ExecutorService getTtlExecutorService(@Nullable ExecutorService executorService) {\n        if (TtlAgentStatus.getInstance().isTtlAgentLoaded() || executorService == null || executorService instanceof TtlEnhanced) {\n            return executorService;\n        }\n        return new ExecutorServiceTtlWrapper(executorService, true);\n    }\n\n\n    /**\n     * {@link TransmittableThreadLocal} Wrapper of {@link ScheduledExecutorService},\n     * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link Callable}\n     * to the execution time of {@link Runnable} or {@link Callable}.\n     *\n     * @param scheduledExecutorService input scheduledExecutorService\n     * @return wrapped scheduledExecutorService\n     * @see com.alibaba.ttl3.TtlRunnable#get(Runnable, boolean, boolean)\n     * @see com.alibaba.ttl3.TtlCallable#get(Callable, boolean, boolean)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ScheduledExecutorService getTtlScheduledExecutorService(@Nullable ScheduledExecutorService scheduledExecutorService) {\n        if (TtlAgentStatus.getInstance().isTtlAgentLoaded() || scheduledExecutorService == null || scheduledExecutorService instanceof TtlEnhanced) {\n            return scheduledExecutorService;\n        }\n        return new ScheduledExecutorServiceTtlWrapper(scheduledExecutorService, true);\n    }\n\n    /**\n     * check the executor is a TTL executor wrapper or not.\n     * <p>\n     * if the parameter executor is TTL wrapper, return {@code true}, otherwise {@code false}.\n     * <p>\n     * NOTE: if input executor is {@code null}, return {@code false}.\n     *\n     * @param executor input executor\n     * @param <T>      Executor type\n     * @see #getTtlExecutor(Executor)\n     * @see #getTtlExecutorService(ExecutorService)\n     * @see #getTtlScheduledExecutorService(ScheduledExecutorService)\n     * @see #unwrapTtlExecutor(Executor)\n     */\n    public static <T extends Executor> boolean isTtlExecutor(@Nullable T executor) {\n        return executor instanceof TtlWrapper;\n    }\n\n    /**\n     * Unwrap TTL executor wrapper to the original/underneath one.\n     * <p>\n     * if the parameter executor is TTL wrapper, return the original/underneath executor;\n     * otherwise, just return the input parameter executor.\n     * <p>\n     * NOTE: if input executor is {@code null}, return {@code null}.\n     *\n     * @param executor input executor\n     * @param <T>      Executor type\n     * @see #getTtlExecutor(Executor)\n     * @see #getTtlExecutorService(ExecutorService)\n     * @see #getTtlScheduledExecutorService(ScheduledExecutorService)\n     * @see #isTtlExecutor(Executor)\n     * @see com.alibaba.ttl3.TtlWrappers#unwrap(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    @SuppressWarnings(\"unchecked\")\n    public static <T extends Executor> T unwrapTtlExecutor(@Nullable T executor) {\n        if (!isTtlExecutor(executor)) return executor;\n\n        return (T) ((ExecutorTtlWrapper) executor).unwrap();\n    }\n\n    /**\n     * Wrapper of {@link ThreadFactory}, disable inheritable.\n     *\n     * @param threadFactory input thread factory\n     * @see TtlExecutors#getDisableInheritableForkJoinWorkerThreadFactory\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ThreadFactory getDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) {\n        if (threadFactory == null || isDisableInheritableThreadFactory(threadFactory)) return threadFactory;\n\n        return new DisableInheritableThreadFactoryWrapper(threadFactory);\n    }\n\n    /**\n     * Wrapper of {@link Executors#defaultThreadFactory()}, disable inheritable.\n     *\n     * @see #getDisableInheritableThreadFactory(ThreadFactory)\n     * @see TtlExecutors#getDefaultDisableInheritableForkJoinWorkerThreadFactory()\n     */\n    @NonNull\n    public static ThreadFactory getDefaultDisableInheritableThreadFactory() {\n        return getDisableInheritableThreadFactory(Executors.defaultThreadFactory());\n    }\n\n    /**\n     * check the {@link ThreadFactory} is {@code DisableInheritableThreadFactory} or not.\n     *\n     * @see TtlExecutors#getDisableInheritableForkJoinWorkerThreadFactory\n     * @see #getDefaultDisableInheritableThreadFactory()\n     */\n    public static boolean isDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) {\n        return threadFactory instanceof DisableInheritableThreadFactoryWrapper;\n    }\n\n    /**\n     * Unwrap {@code DisableInheritableThreadFactory} to the original/underneath one.\n     *\n     * @see #getDisableInheritableThreadFactory(ThreadFactory)\n     * @see #getDefaultDisableInheritableThreadFactory()\n     * @see #isDisableInheritableThreadFactory(ThreadFactory)\n     * @see TtlExecutors#unwrapDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory)\n     * @see com.alibaba.ttl3.TtlWrappers#unwrap(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ThreadFactory unwrapDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) {\n        if (!isDisableInheritableThreadFactory(threadFactory)) return threadFactory;\n\n        return ((DisableInheritableThreadFactoryWrapper) threadFactory).unwrap();\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    // ForkJoinPool utils\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * Wrapper of {@link ForkJoinWorkerThreadFactory}, disable inheritable.\n     *\n     * @param threadFactory input thread factory\n     * @see TtlExecutors#getDisableInheritableThreadFactory(ThreadFactory)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ForkJoinWorkerThreadFactory getDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) {\n        if (threadFactory == null || isDisableInheritableForkJoinWorkerThreadFactory(threadFactory))\n            return threadFactory;\n\n        return new DisableInheritableForkJoinWorkerThreadFactoryWrapper(threadFactory);\n    }\n\n    /**\n     * Wrapper of {@link ForkJoinPool#defaultForkJoinWorkerThreadFactory}, disable inheritable.\n     *\n     * @see #getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory)\n     * @see TtlExecutors#getDefaultDisableInheritableThreadFactory()\n     */\n    @NonNull\n    public static ForkJoinWorkerThreadFactory getDefaultDisableInheritableForkJoinWorkerThreadFactory() {\n        return getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinPool.defaultForkJoinWorkerThreadFactory);\n    }\n\n    /**\n     * check the {@link ForkJoinWorkerThreadFactory} is {@code DisableInheritableForkJoinWorkerThreadFactory} or not.\n     *\n     * @see #getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory)\n     * @see #getDefaultDisableInheritableForkJoinWorkerThreadFactory()\n     */\n    public static boolean isDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) {\n        return threadFactory instanceof DisableInheritableForkJoinWorkerThreadFactoryWrapper;\n    }\n\n    /**\n     * Unwrap {@code DisableInheritableForkJoinWorkerThreadFactory} to the original/underneath one.\n     *\n     * @see com.alibaba.ttl3.TtlWrappers#unwrap(Object)\n     * @see TtlExecutors#unwrapDisableInheritableThreadFactory(ThreadFactory)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ForkJoinWorkerThreadFactory unwrapDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) {\n        if (!isDisableInheritableForkJoinWorkerThreadFactory(threadFactory)) return threadFactory;\n\n        return ((DisableInheritableForkJoinWorkerThreadFactoryWrapper) threadFactory).unwrap();\n    }\n\n    ///////////////////////////////////////////////////////////////////////////\n    // Comparator utils\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * Wrapper of {@code Comparator<Runnable>} which unwrap {@link com.alibaba.ttl3.TtlRunnable} before compare,\n     * aka {@code TtlRunnableUnwrapComparator}.\n     * <p>\n     * Prepared for {@code comparator} parameter of constructor\n     * {@link PriorityBlockingQueue#PriorityBlockingQueue(int, Comparator)}.\n     * <p>\n     * {@link PriorityBlockingQueue} can be used by constructor\n     * {@link ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue)}.\n     *\n     * @param comparator input comparator\n     * @return wrapped comparator\n     * @see ThreadPoolExecutor\n     * @see ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue)\n     * @see PriorityBlockingQueue\n     * @see PriorityBlockingQueue#PriorityBlockingQueue(int, Comparator)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static Comparator<Runnable> getTtlRunnableUnwrapComparator(@Nullable Comparator<Runnable> comparator) {\n        if (comparator == null || isTtlRunnableUnwrapComparator(comparator)) return comparator;\n\n        return new TtlUnwrapComparator<>(comparator);\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private static final Comparator INSTANCE = new TtlUnwrapComparator(ComparableComparator.INSTANCE);\n\n    /**\n     * {@code TtlRunnableUnwrapComparator} that compares {@link Comparable Comparable} objects.\n     *\n     * @see #getTtlRunnableUnwrapComparator(Comparator)\n     */\n    @NonNull\n    @SuppressWarnings(\"unchecked\")\n    public static Comparator<Runnable> getTtlRunnableUnwrapComparatorForComparableRunnable() {\n        return (Comparator<Runnable>) INSTANCE;\n    }\n\n    /**\n     * check the {@code Comparator<Runnable>} is a wrapper {@code TtlRunnableUnwrapComparator} or not.\n     *\n     * @see #getTtlRunnableUnwrapComparator(Comparator)\n     * @see #getTtlRunnableUnwrapComparatorForComparableRunnable()\n     */\n    public static boolean isTtlRunnableUnwrapComparator(@Nullable Comparator<Runnable> comparator) {\n        return comparator instanceof TtlUnwrapComparator;\n    }\n\n    /**\n     * Unwrap {@code TtlRunnableUnwrapComparator} to the original/underneath {@code Comparator<Runnable>}.\n     *\n     * @see #getTtlRunnableUnwrapComparator(Comparator)\n     * @see #getTtlRunnableUnwrapComparatorForComparableRunnable()\n     * @see #isTtlRunnableUnwrapComparator(Comparator)\n     * @see com.alibaba.ttl3.TtlWrappers#unwrap(Object)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static Comparator<Runnable> unwrapTtlRunnableUnwrapComparator(@Nullable Comparator<Runnable> comparator) {\n        if (!isTtlRunnableUnwrapComparator(comparator)) return comparator;\n\n        return ((TtlUnwrapComparator<Runnable>) comparator).unwrap();\n    }\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlExecutors() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/executor/TtlUnwrapComparator.java",
    "content": "package com.alibaba.ttl3.executor;\n\nimport com.alibaba.ttl3.TtlWrappers;\nimport com.alibaba.ttl3.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.Comparator;\n\n/**\n * @see TtlExecutors#getTtlRunnableUnwrapComparator(Comparator)\n * @see TtlExecutors#isTtlRunnableUnwrapComparator(Comparator)\n * @see TtlExecutors#unwrapTtlRunnableUnwrapComparator(Comparator)\n */\nfinal class TtlUnwrapComparator<T> implements Comparator<T>, TtlWrapper<Comparator<T>> {\n    private final Comparator<T> comparator;\n\n    public TtlUnwrapComparator(@NonNull Comparator<T> comparator) {\n        this.comparator = comparator;\n    }\n\n    @Override\n    public int compare(T o1, T o2) {\n        return comparator.compare(TtlWrappers.unwrap(o1), TtlWrappers.unwrap(o2));\n    }\n\n    @NonNull\n    @Override\n    public Comparator<T> unwrap() {\n        return comparator;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        TtlUnwrapComparator<?> that = (TtlUnwrapComparator<?>) o;\n\n        return comparator.equals(that.comparator);\n    }\n\n    @Override\n    public int hashCode() {\n        return comparator.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return \"TtlUnwrapComparator{comparator=\" + comparator + '}';\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/executor/package-info.java",
    "content": "/**\n * {@code TTL} wrap/decoration utils for {@code executor}s.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.executor.TtlExecutors\n */\npackage com.alibaba.ttl3.executor;\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/internal/util/Assert.java",
    "content": "/*\n * Copyright 2002-2020 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.alibaba.ttl3.internal.util;\n\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This source code file is copied from spring v5.3.24:\n//\n// https://github.com/spring-projects/spring-framework/blob/v5.3.24/spring-core/src/main/java/org/springframework/util/Assert.java\n//\n// with adoption:\n// - remove unused elements\n// - adjust visible modifier and code format\n//\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\nimport edu.umd.cs.findbugs.annotations.Nullable;\n\n/**\n * Assertion utility class that assists in validating arguments.\n *\n * <p>Useful for identifying programmer errors early and clearly at runtime.\n *\n * <p>For example, if the contract of a public method states it does not\n * allow {@code null} arguments, {@code Assert} can be used to validate that\n * contract. Doing this clearly indicates a contract violation when it\n * occurs and protects the class's invariants.\n *\n * <p>Typically used to validate method arguments rather than configuration\n * properties, to check for cases that are usually programmer errors rather\n * than configuration errors. In contrast to configuration initialization\n * code, there is usually no point in falling back to defaults in such methods.\n *\n * <p>This class is similar to JUnit's assertion library. If an argument value is\n * deemed invalid, an {@link IllegalArgumentException} is thrown (typically).\n * For example:\n *\n * <pre class=\"code\">\n * Assert.notNull(clazz, \"The class must not be null\");\n * Assert.isTrue(i &gt; 0, \"The value must be greater than zero\");</pre>\n *\n * <p>Mainly for internal use within the framework; for a more comprehensive suite\n * of assertion utilities consider {@code org.apache.commons.lang3.Validate} from\n * <a href=\"https://commons.apache.org/proper/commons-lang/\">Apache Commons Lang</a>,\n * Google Guava's\n * <a href=\"https://github.com/google/guava/wiki/PreconditionsExplained\">Preconditions</a>,\n * or similar third-party libraries.\n *\n * @author Keith Donald\n * @author Juergen Hoeller\n * @author Sam Brannen\n * @author Colin Sampaleanu\n * @author Rob Harrop\n */\nfinal class Assert {\n\n    /**\n     * Assert a boolean expression, throwing an {@code IllegalStateException}\n     * if the expression evaluates to {@code false}.\n     * <p>Call {@link #isTrue} if you wish to throw an {@code IllegalArgumentException}\n     * on an assertion failure.\n     * <pre class=\"code\">Assert.state(id == null, \"The id property must not already be initialized\");</pre>\n     *\n     * @param expression a boolean expression\n     * @param message    the exception message to use if the assertion fails\n     * @throws IllegalStateException if {@code expression} is {@code false}\n     */\n    public static void state(boolean expression, String message) {\n        if (!expression) {\n            throw new IllegalStateException(message);\n        }\n    }\n\n    /**\n     * Assert a boolean expression, throwing an {@code IllegalArgumentException}\n     * if the expression evaluates to {@code false}.\n     * <pre class=\"code\">Assert.isTrue(i &gt; 0, \"The value must be greater than zero\");</pre>\n     *\n     * @param expression a boolean expression\n     * @param message    the exception message to use if the assertion fails\n     * @throws IllegalArgumentException if {@code expression} is {@code false}\n     */\n    public static void isTrue(boolean expression, String message) {\n        if (!expression) {\n            throw new IllegalArgumentException(message);\n        }\n    }\n\n    /**\n     * Assert that an object is not {@code null}.\n     * <pre class=\"code\">Assert.notNull(clazz, \"The class must not be null\");</pre>\n     *\n     * @param object  the object to check\n     * @param message the exception message to use if the assertion fails\n     * @throws IllegalArgumentException if the object is {@code null}\n     */\n    public static void notNull(@Nullable Object object, String message) {\n        if (object == null) {\n            throw new IllegalArgumentException(message);\n        }\n    }\n\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/internal/util/ConcurrentReferenceHashMap.java",
    "content": "/*\n * Copyright 2002-2021 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.alibaba.ttl3.internal.util;\n\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This source code file is copied from spring v5.3.24:\n//\n// https://github.com/spring-projects/spring-framework/blob/v5.3.24/spring-core/src/main/java/org/springframework/util/ConcurrentReferenceHashMap.java\n//\n// with adoption:\n// - adjust visible modifier and code format\n//\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.lang.ref.ReferenceQueue;\nimport java.lang.ref.SoftReference;\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Array;\nimport java.util.AbstractMap;\nimport java.util.AbstractSet;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * A {@link ConcurrentHashMap} that uses {@link ReferenceType#SOFT soft} or\n * {@linkplain ReferenceType#WEAK weak} references for both {@code keys} and {@code values}.\n *\n * <p>This class can be used as an alternative to\n * {@code Collections.synchronizedMap(new WeakHashMap<K, Reference<V>>())} in order to\n * support better performance when accessed concurrently. This implementation follows the\n * same design constraints as {@link ConcurrentHashMap} with the exception that\n * {@code null} values and {@code null} keys are supported.\n *\n * <p><b>NOTE:</b> The use of references means that there is no guarantee that items\n * placed into the map will be subsequently available. The garbage collector may discard\n * references at any time, so it may appear that an unknown thread is silently removing\n * entries.\n *\n * <p>If not explicitly specified, this implementation will use\n * {@linkplain SoftReference soft entry references}.\n *\n * @param <K> the key type\n * @param <V> the value type\n * @author Phillip Webb\n * @author Juergen Hoeller\n */\n@SuppressWarnings(\"ALL\")\n// Is there a class annotation in FindBugs to ignore all warning in a file\n// https://stackoverflow.com/questions/13398685\n@SuppressFBWarnings\nclass ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> {\n\n    private static final int DEFAULT_INITIAL_CAPACITY = 16;\n\n    private static final float DEFAULT_LOAD_FACTOR = 0.75f;\n\n    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;\n\n    private static final ReferenceType DEFAULT_REFERENCE_TYPE = ReferenceType.SOFT;\n\n    private static final int MAXIMUM_CONCURRENCY_LEVEL = 1 << 16;\n\n    private static final int MAXIMUM_SEGMENT_SIZE = 1 << 30;\n\n\n    /**\n     * Array of segments indexed using the high order bits from the hash.\n     */\n    private final Segment[] segments;\n\n    /**\n     * When the average number of references per table exceeds this value resize will be attempted.\n     */\n    private final float loadFactor;\n\n    /**\n     * The reference type: SOFT or WEAK.\n     */\n    private final ReferenceType referenceType;\n\n    /**\n     * The shift value used to calculate the size of the segments array and an index from the hash.\n     */\n    private final int shift;\n\n    /**\n     * Late binding entry set.\n     */\n    @Nullable\n    private volatile Set<Map.Entry<K, V>> entrySet;\n\n\n    /**\n     * Create a new {@code ConcurrentReferenceHashMap} instance.\n     */\n    public ConcurrentReferenceHashMap() {\n        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL, DEFAULT_REFERENCE_TYPE);\n    }\n\n    /**\n     * Create a new {@code ConcurrentReferenceHashMap} instance.\n     *\n     * @param initialCapacity the initial capacity of the map\n     */\n    public ConcurrentReferenceHashMap(int initialCapacity) {\n        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL, DEFAULT_REFERENCE_TYPE);\n    }\n\n    /**\n     * Create a new {@code ConcurrentReferenceHashMap} instance.\n     *\n     * @param initialCapacity the initial capacity of the map\n     * @param loadFactor      the load factor. When the average number of references per table\n     *                        exceeds this value resize will be attempted\n     */\n    public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor) {\n        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL, DEFAULT_REFERENCE_TYPE);\n    }\n\n    /**\n     * Create a new {@code ConcurrentReferenceHashMap} instance.\n     *\n     * @param initialCapacity  the initial capacity of the map\n     * @param concurrencyLevel the expected number of threads that will concurrently\n     *                         write to the map\n     */\n    public ConcurrentReferenceHashMap(int initialCapacity, int concurrencyLevel) {\n        this(initialCapacity, DEFAULT_LOAD_FACTOR, concurrencyLevel, DEFAULT_REFERENCE_TYPE);\n    }\n\n    /**\n     * Create a new {@code ConcurrentReferenceHashMap} instance.\n     *\n     * @param initialCapacity the initial capacity of the map\n     * @param referenceType   the reference type used for entries (soft or weak)\n     */\n    public ConcurrentReferenceHashMap(int initialCapacity, ReferenceType referenceType) {\n        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL, referenceType);\n    }\n\n    /**\n     * Create a new {@code ConcurrentReferenceHashMap} instance.\n     *\n     * @param initialCapacity  the initial capacity of the map\n     * @param loadFactor       the load factor. When the average number of references per\n     *                         table exceeds this value, resize will be attempted.\n     * @param concurrencyLevel the expected number of threads that will concurrently\n     *                         write to the map\n     */\n    public ConcurrentReferenceHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) {\n        this(initialCapacity, loadFactor, concurrencyLevel, DEFAULT_REFERENCE_TYPE);\n    }\n\n    /**\n     * Create a new {@code ConcurrentReferenceHashMap} instance.\n     *\n     * @param initialCapacity  the initial capacity of the map\n     * @param loadFactor       the load factor. When the average number of references per\n     *                         table exceeds this value, resize will be attempted.\n     * @param concurrencyLevel the expected number of threads that will concurrently\n     *                         write to the map\n     * @param referenceType    the reference type used for entries (soft or weak)\n     */\n    @SuppressWarnings(\"unchecked\")\n    public ConcurrentReferenceHashMap(\n            int initialCapacity, float loadFactor, int concurrencyLevel, ReferenceType referenceType) {\n\n        Assert.isTrue(initialCapacity >= 0, \"Initial capacity must not be negative\");\n        Assert.isTrue(loadFactor > 0f, \"Load factor must be positive\");\n        Assert.isTrue(concurrencyLevel > 0, \"Concurrency level must be positive\");\n        Assert.notNull(referenceType, \"Reference type must not be null\");\n        this.loadFactor = loadFactor;\n        this.shift = calculateShift(concurrencyLevel, MAXIMUM_CONCURRENCY_LEVEL);\n        int size = 1 << this.shift;\n        this.referenceType = referenceType;\n        int roundedUpSegmentCapacity = (int) ((initialCapacity + size - 1L) / size);\n        int initialSize = 1 << calculateShift(roundedUpSegmentCapacity, MAXIMUM_SEGMENT_SIZE);\n        Segment[] segments = (Segment[]) Array.newInstance(Segment.class, size);\n        int resizeThreshold = (int) (initialSize * getLoadFactor());\n        for (int i = 0; i < segments.length; i++) {\n            segments[i] = new Segment(initialSize, resizeThreshold);\n        }\n        this.segments = segments;\n    }\n\n\n    protected final float getLoadFactor() {\n        return this.loadFactor;\n    }\n\n    protected final int getSegmentsSize() {\n        return this.segments.length;\n    }\n\n    protected final Segment getSegment(int index) {\n        return this.segments[index];\n    }\n\n    /**\n     * Factory method that returns the {@link ReferenceManager}.\n     * This method will be called once for each {@link Segment}.\n     *\n     * @return a new reference manager\n     */\n    protected ReferenceManager createReferenceManager() {\n        return new ReferenceManager();\n    }\n\n    /**\n     * Get the hash for a given object, apply an additional hash function to reduce\n     * collisions. This implementation uses the same Wang/Jenkins algorithm as\n     * {@link ConcurrentHashMap}. Subclasses can override to provide alternative hashing.\n     *\n     * @param o the object to hash (may be null)\n     * @return the resulting hash code\n     */\n    protected int getHash(@Nullable Object o) {\n        int hash = (o != null ? o.hashCode() : 0);\n        hash += (hash << 15) ^ 0xffffcd7d;\n        hash ^= (hash >>> 10);\n        hash += (hash << 3);\n        hash ^= (hash >>> 6);\n        hash += (hash << 2) + (hash << 14);\n        hash ^= (hash >>> 16);\n        return hash;\n    }\n\n    @Override\n    @Nullable\n    public V get(@Nullable Object key) {\n        Reference<K, V> ref = getReference(key, Restructure.WHEN_NECESSARY);\n        Entry<K, V> entry = (ref != null ? ref.get() : null);\n        return (entry != null ? entry.getValue() : null);\n    }\n\n    @Override\n    @Nullable\n    public V getOrDefault(@Nullable Object key, @Nullable V defaultValue) {\n        Reference<K, V> ref = getReference(key, Restructure.WHEN_NECESSARY);\n        Entry<K, V> entry = (ref != null ? ref.get() : null);\n        return (entry != null ? entry.getValue() : defaultValue);\n    }\n\n    @Override\n    public boolean containsKey(@Nullable Object key) {\n        Reference<K, V> ref = getReference(key, Restructure.WHEN_NECESSARY);\n        Entry<K, V> entry = (ref != null ? ref.get() : null);\n        return (entry != null && ObjectUtils.nullSafeEquals(entry.getKey(), key));\n    }\n\n    /**\n     * Return a {@link Reference} to the {@link Entry} for the specified {@code key},\n     * or {@code null} if not found.\n     *\n     * @param key         the key (can be {@code null})\n     * @param restructure types of restructure allowed during this call\n     * @return the reference, or {@code null} if not found\n     */\n    @Nullable\n    protected final Reference<K, V> getReference(@Nullable Object key, Restructure restructure) {\n        int hash = getHash(key);\n        return getSegmentForHash(hash).getReference(key, hash, restructure);\n    }\n\n    @Override\n    @Nullable\n    public V put(@Nullable K key, @Nullable V value) {\n        return put(key, value, true);\n    }\n\n    @Override\n    @Nullable\n    public V putIfAbsent(@Nullable K key, @Nullable V value) {\n        return put(key, value, false);\n    }\n\n    @Nullable\n    private V put(@Nullable final K key, @Nullable final V value, final boolean overwriteExisting) {\n        return doTask(key, new Task<V>(TaskOption.RESTRUCTURE_BEFORE, TaskOption.RESIZE) {\n            @Override\n            @Nullable\n            protected V execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry, @Nullable Entries<V> entries) {\n                if (entry != null) {\n                    V oldValue = entry.getValue();\n                    if (overwriteExisting) {\n                        entry.setValue(value);\n                    }\n                    return oldValue;\n                }\n                Assert.state(entries != null, \"No entries segment\");\n                entries.add(value);\n                return null;\n            }\n        });\n    }\n\n    @Override\n    @Nullable\n    public V remove(@Nullable Object key) {\n        return doTask(key, new Task<V>(TaskOption.RESTRUCTURE_AFTER, TaskOption.SKIP_IF_EMPTY) {\n            @Override\n            @Nullable\n            protected V execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry) {\n                if (entry != null) {\n                    if (ref != null) {\n                        ref.release();\n                    }\n                    return entry.value;\n                }\n                return null;\n            }\n        });\n    }\n\n    @Override\n    public boolean remove(@Nullable Object key, final @Nullable Object value) {\n        Boolean result = doTask(key, new Task<Boolean>(TaskOption.RESTRUCTURE_AFTER, TaskOption.SKIP_IF_EMPTY) {\n            @Override\n            protected Boolean execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry) {\n                if (entry != null && ObjectUtils.nullSafeEquals(entry.getValue(), value)) {\n                    if (ref != null) {\n                        ref.release();\n                    }\n                    return true;\n                }\n                return false;\n            }\n        });\n        return (Boolean.TRUE.equals(result));\n    }\n\n    @Override\n    public boolean replace(@Nullable K key, final @Nullable V oldValue, final @Nullable V newValue) {\n        Boolean result = doTask(key, new Task<Boolean>(TaskOption.RESTRUCTURE_BEFORE, TaskOption.SKIP_IF_EMPTY) {\n            @Override\n            protected Boolean execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry) {\n                if (entry != null && ObjectUtils.nullSafeEquals(entry.getValue(), oldValue)) {\n                    entry.setValue(newValue);\n                    return true;\n                }\n                return false;\n            }\n        });\n        return (Boolean.TRUE.equals(result));\n    }\n\n    @Override\n    @Nullable\n    public V replace(@Nullable K key, final @Nullable V value) {\n        return doTask(key, new Task<V>(TaskOption.RESTRUCTURE_BEFORE, TaskOption.SKIP_IF_EMPTY) {\n            @Override\n            @Nullable\n            protected V execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry) {\n                if (entry != null) {\n                    V oldValue = entry.getValue();\n                    entry.setValue(value);\n                    return oldValue;\n                }\n                return null;\n            }\n        });\n    }\n\n    @Override\n    public void clear() {\n        for (Segment segment : this.segments) {\n            segment.clear();\n        }\n    }\n\n    /**\n     * Remove any entries that have been garbage collected and are no longer referenced.\n     * Under normal circumstances garbage collected entries are automatically purged as\n     * items are added or removed from the Map. This method can be used to force a purge,\n     * and is useful when the Map is read frequently but updated less often.\n     */\n    public void purgeUnreferencedEntries() {\n        for (Segment segment : this.segments) {\n            segment.restructureIfNecessary(false);\n        }\n    }\n\n\n    @Override\n    public int size() {\n        int size = 0;\n        for (Segment segment : this.segments) {\n            size += segment.getCount();\n        }\n        return size;\n    }\n\n    @Override\n    public boolean isEmpty() {\n        for (Segment segment : this.segments) {\n            if (segment.getCount() > 0) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public Set<Map.Entry<K, V>> entrySet() {\n        Set<Map.Entry<K, V>> entrySet = this.entrySet;\n        if (entrySet == null) {\n            entrySet = new EntrySet();\n            this.entrySet = entrySet;\n        }\n        return entrySet;\n    }\n\n    @Nullable\n    private <T> T doTask(@Nullable Object key, Task<T> task) {\n        int hash = getHash(key);\n        return getSegmentForHash(hash).doTask(hash, key, task);\n    }\n\n    private Segment getSegmentForHash(int hash) {\n        return this.segments[(hash >>> (32 - this.shift)) & (this.segments.length - 1)];\n    }\n\n    /**\n     * Calculate a shift value that can be used to create a power-of-two value between\n     * the specified maximum and minimum values.\n     *\n     * @param minimumValue the minimum value\n     * @param maximumValue the maximum value\n     * @return the calculated shift (use {@code 1 << shift} to obtain a value)\n     */\n    protected static int calculateShift(int minimumValue, int maximumValue) {\n        int shift = 0;\n        int value = 1;\n        while (value < minimumValue && value < maximumValue) {\n            value <<= 1;\n            shift++;\n        }\n        return shift;\n    }\n\n\n    /**\n     * Various reference types supported by this map.\n     */\n    public enum ReferenceType {\n\n        /**\n         * Use {@link SoftReference SoftReferences}.\n         */\n        SOFT,\n\n        /**\n         * Use {@link WeakReference WeakReferences}.\n         */\n        WEAK\n    }\n\n\n    /**\n     * A single segment used to divide the map to allow better concurrent performance.\n     */\n    @SuppressWarnings(\"serial\")\n    @SuppressFBWarnings(\"EI_EXPOSE_REP2\")\n    protected final class Segment extends ReentrantLock {\n\n        private final ReferenceManager referenceManager;\n\n        private final int initialSize;\n\n        /**\n         * Array of references indexed using the low order bits from the hash.\n         * This property should only be set along with {@code resizeThreshold}.\n         */\n        private volatile Reference<K, V>[] references;\n\n        /**\n         * The total number of references contained in this segment. This includes chained\n         * references and references that have been garbage collected but not purged.\n         */\n        private final AtomicInteger count = new AtomicInteger();\n\n        /**\n         * The threshold when resizing of the references should occur. When {@code count}\n         * exceeds this value references will be resized.\n         */\n        private int resizeThreshold;\n\n        public Segment(int initialSize, int resizeThreshold) {\n            this.referenceManager = createReferenceManager();\n            this.initialSize = initialSize;\n            this.references = createReferenceArray(initialSize);\n            this.resizeThreshold = resizeThreshold;\n        }\n\n        @Nullable\n        public Reference<K, V> getReference(@Nullable Object key, int hash, Restructure restructure) {\n            if (restructure == Restructure.WHEN_NECESSARY) {\n                restructureIfNecessary(false);\n            }\n            if (this.count.get() == 0) {\n                return null;\n            }\n            // Use a local copy to protect against other threads writing\n            Reference<K, V>[] references = this.references;\n            int index = getIndex(hash, references);\n            Reference<K, V> head = references[index];\n            return findInChain(head, key, hash);\n        }\n\n        /**\n         * Apply an update operation to this segment.\n         * The segment will be locked during the update.\n         *\n         * @param hash the hash of the key\n         * @param key  the key\n         * @param task the update operation\n         * @return the result of the operation\n         */\n        @Nullable\n        public <T> T doTask(final int hash, @Nullable final Object key, final Task<T> task) {\n            boolean resize = task.hasOption(TaskOption.RESIZE);\n            if (task.hasOption(TaskOption.RESTRUCTURE_BEFORE)) {\n                restructureIfNecessary(resize);\n            }\n            if (task.hasOption(TaskOption.SKIP_IF_EMPTY) && this.count.get() == 0) {\n                return task.execute(null, null, null);\n            }\n            lock();\n            try {\n                final int index = getIndex(hash, this.references);\n                final Reference<K, V> head = this.references[index];\n                Reference<K, V> ref = findInChain(head, key, hash);\n                Entry<K, V> entry = (ref != null ? ref.get() : null);\n                Entries<V> entries = value -> {\n                    @SuppressWarnings(\"unchecked\")\n                    Entry<K, V> newEntry = new Entry<>((K) key, value);\n                    Reference<K, V> newReference = Segment.this.referenceManager.createReference(newEntry, hash, head);\n                    Segment.this.references[index] = newReference;\n                    Segment.this.count.incrementAndGet();\n                };\n                return task.execute(ref, entry, entries);\n            } finally {\n                unlock();\n                if (task.hasOption(TaskOption.RESTRUCTURE_AFTER)) {\n                    restructureIfNecessary(resize);\n                }\n            }\n        }\n\n        /**\n         * Clear all items from this segment.\n         */\n        public void clear() {\n            if (this.count.get() == 0) {\n                return;\n            }\n            lock();\n            try {\n                this.references = createReferenceArray(this.initialSize);\n                this.resizeThreshold = (int) (this.references.length * getLoadFactor());\n                this.count.set(0);\n            } finally {\n                unlock();\n            }\n        }\n\n        /**\n         * Restructure the underlying data structure when it becomes necessary. This\n         * method can increase the size of the references table as well as purge any\n         * references that have been garbage collected.\n         *\n         * @param allowResize if resizing is permitted\n         */\n        protected final void restructureIfNecessary(boolean allowResize) {\n            int currCount = this.count.get();\n            boolean needsResize = allowResize && (currCount > 0 && currCount >= this.resizeThreshold);\n            Reference<K, V> ref = this.referenceManager.pollForPurge();\n            if (ref != null || (needsResize)) {\n                restructure(allowResize, ref);\n            }\n        }\n\n        private void restructure(boolean allowResize, @Nullable Reference<K, V> ref) {\n            boolean needsResize;\n            lock();\n            try {\n                int countAfterRestructure = this.count.get();\n                Set<Reference<K, V>> toPurge = Collections.emptySet();\n                if (ref != null) {\n                    toPurge = new HashSet<>();\n                    while (ref != null) {\n                        toPurge.add(ref);\n                        ref = this.referenceManager.pollForPurge();\n                    }\n                }\n                countAfterRestructure -= toPurge.size();\n\n                // Recalculate taking into account count inside lock and items that\n                // will be purged\n                needsResize = (countAfterRestructure > 0 && countAfterRestructure >= this.resizeThreshold);\n                boolean resizing = false;\n                int restructureSize = this.references.length;\n                if (allowResize && needsResize && restructureSize < MAXIMUM_SEGMENT_SIZE) {\n                    restructureSize <<= 1;\n                    resizing = true;\n                }\n\n                // Either create a new table or reuse the existing one\n                Reference<K, V>[] restructured =\n                        (resizing ? createReferenceArray(restructureSize) : this.references);\n\n                // Restructure\n                for (int i = 0; i < this.references.length; i++) {\n                    ref = this.references[i];\n                    if (!resizing) {\n                        restructured[i] = null;\n                    }\n                    while (ref != null) {\n                        if (!toPurge.contains(ref)) {\n                            Entry<K, V> entry = ref.get();\n                            if (entry != null) {\n                                int index = getIndex(ref.getHash(), restructured);\n                                restructured[index] = this.referenceManager.createReference(\n                                        entry, ref.getHash(), restructured[index]);\n                            }\n                        }\n                        ref = ref.getNext();\n                    }\n                }\n\n                // Replace volatile members\n                if (resizing) {\n                    this.references = restructured;\n                    this.resizeThreshold = (int) (this.references.length * getLoadFactor());\n                }\n                this.count.set(Math.max(countAfterRestructure, 0));\n            } finally {\n                unlock();\n            }\n        }\n\n        @Nullable\n        private Reference<K, V> findInChain(Reference<K, V> ref, @Nullable Object key, int hash) {\n            Reference<K, V> currRef = ref;\n            while (currRef != null) {\n                if (currRef.getHash() == hash) {\n                    Entry<K, V> entry = currRef.get();\n                    if (entry != null) {\n                        K entryKey = entry.getKey();\n                        if (ObjectUtils.nullSafeEquals(entryKey, key)) {\n                            return currRef;\n                        }\n                    }\n                }\n                currRef = currRef.getNext();\n            }\n            return null;\n        }\n\n        @SuppressWarnings({\"unchecked\"})\n        private Reference<K, V>[] createReferenceArray(int size) {\n            return new Reference[size];\n        }\n\n        private int getIndex(int hash, Reference<K, V>[] references) {\n            return (hash & (references.length - 1));\n        }\n\n        /**\n         * Return the size of the current references array.\n         */\n        public final int getSize() {\n            return this.references.length;\n        }\n\n        /**\n         * Return the total number of references in this segment.\n         */\n        public final int getCount() {\n            return this.count.get();\n        }\n    }\n\n\n    /**\n     * A reference to an {@link Entry} contained in the map. Implementations are usually\n     * wrappers around specific Java reference implementations (e.g., {@link SoftReference}).\n     *\n     * @param <K> the key type\n     * @param <V> the value type\n     */\n    protected interface Reference<K, V> {\n\n        /**\n         * Return the referenced entry, or {@code null} if the entry is no longer available.\n         */\n        @Nullable\n        Entry<K, V> get();\n\n        /**\n         * Return the hash for the reference.\n         */\n        int getHash();\n\n        /**\n         * Return the next reference in the chain, or {@code null} if none.\n         */\n        @Nullable\n        Reference<K, V> getNext();\n\n        /**\n         * Release this entry and ensure that it will be returned from\n         * {@code ReferenceManager#pollForPurge()}.\n         */\n        void release();\n    }\n\n\n    /**\n     * A single map entry.\n     *\n     * @param <K> the key type\n     * @param <V> the value type\n     */\n    @SuppressFBWarnings(\"NP_METHOD_PARAMETER_TIGHTENS_ANNOTATION\")\n    protected static final class Entry<K, V> implements Map.Entry<K, V> {\n\n        @Nullable\n        private final K key;\n\n        @Nullable\n        private volatile V value;\n\n        public Entry(@Nullable K key, @Nullable V value) {\n            this.key = key;\n            this.value = value;\n        }\n\n        @Override\n        @Nullable\n        public K getKey() {\n            return this.key;\n        }\n\n        @Override\n        @Nullable\n        public V getValue() {\n            return this.value;\n        }\n\n        @Override\n        @Nullable\n        public V setValue(@Nullable V value) {\n            V previous = this.value;\n            this.value = value;\n            return previous;\n        }\n\n        @Override\n        public String toString() {\n            return (this.key + \"=\" + this.value);\n        }\n\n        @Override\n        @SuppressWarnings(\"rawtypes\")\n        public final boolean equals(@Nullable Object other) {\n            if (this == other) {\n                return true;\n            }\n            if (!(other instanceof Map.Entry)) {\n                return false;\n            }\n            Map.Entry otherEntry = (Map.Entry) other;\n            return (ObjectUtils.nullSafeEquals(getKey(), otherEntry.getKey()) &&\n                    ObjectUtils.nullSafeEquals(getValue(), otherEntry.getValue()));\n        }\n\n        @Override\n        public final int hashCode() {\n            return (ObjectUtils.nullSafeHashCode(this.key) ^ ObjectUtils.nullSafeHashCode(this.value));\n        }\n    }\n\n\n    /**\n     * A task that can be {@link Segment#doTask run} against a {@link Segment}.\n     */\n    private abstract class Task<T> {\n\n        private final EnumSet<TaskOption> options;\n\n        public Task(TaskOption... options) {\n            this.options = (options.length == 0 ? EnumSet.noneOf(TaskOption.class) : EnumSet.of(options[0], options));\n        }\n\n        public boolean hasOption(TaskOption option) {\n            return this.options.contains(option);\n        }\n\n        /**\n         * Execute the task.\n         *\n         * @param ref     the found reference (or {@code null})\n         * @param entry   the found entry (or {@code null})\n         * @param entries access to the underlying entries\n         * @return the result of the task\n         * @see #execute(Reference, Entry)\n         */\n        @Nullable\n        protected T execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry, @Nullable Entries<V> entries) {\n            return execute(ref, entry);\n        }\n\n        /**\n         * Convenience method that can be used for tasks that do not need access to {@link Entries}.\n         *\n         * @param ref   the found reference (or {@code null})\n         * @param entry the found entry (or {@code null})\n         * @return the result of the task\n         * @see #execute(Reference, Entry, Entries)\n         */\n        @Nullable\n        protected T execute(@Nullable Reference<K, V> ref, @Nullable Entry<K, V> entry) {\n            return null;\n        }\n    }\n\n\n    /**\n     * Various options supported by a {@code Task}.\n     */\n    private enum TaskOption {\n\n        RESTRUCTURE_BEFORE, RESTRUCTURE_AFTER, SKIP_IF_EMPTY, RESIZE\n    }\n\n\n    /**\n     * Allows a task access to {@link ConcurrentReferenceHashMap.Segment} entries.\n     */\n    private interface Entries<V> {\n\n        /**\n         * Add a new entry with the specified value.\n         *\n         * @param value the value to add\n         */\n        void add(@Nullable V value);\n    }\n\n\n    /**\n     * Internal entry-set implementation.\n     */\n    private class EntrySet extends AbstractSet<Map.Entry<K, V>> {\n\n        @Override\n        public Iterator<Map.Entry<K, V>> iterator() {\n            return new EntryIterator();\n        }\n\n        @Override\n        public boolean contains(@Nullable Object o) {\n            if (o instanceof Map.Entry<?, ?>) {\n                Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;\n                Reference<K, V> ref = ConcurrentReferenceHashMap.this.getReference(entry.getKey(), Restructure.NEVER);\n                Entry<K, V> otherEntry = (ref != null ? ref.get() : null);\n                if (otherEntry != null) {\n                    return ObjectUtils.nullSafeEquals(entry.getValue(), otherEntry.getValue());\n                }\n            }\n            return false;\n        }\n\n        @Override\n        public boolean remove(Object o) {\n            if (o instanceof Map.Entry<?, ?>) {\n                Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;\n                return ConcurrentReferenceHashMap.this.remove(entry.getKey(), entry.getValue());\n            }\n            return false;\n        }\n\n        @Override\n        public int size() {\n            return ConcurrentReferenceHashMap.this.size();\n        }\n\n        @Override\n        public void clear() {\n            ConcurrentReferenceHashMap.this.clear();\n        }\n    }\n\n\n    /**\n     * Internal entry iterator implementation.\n     */\n    private class EntryIterator implements Iterator<Map.Entry<K, V>> {\n\n        private int segmentIndex;\n\n        private int referenceIndex;\n\n        @Nullable\n        private Reference<K, V>[] references;\n\n        @Nullable\n        private Reference<K, V> reference;\n\n        @Nullable\n        private Entry<K, V> next;\n\n        @Nullable\n        private Entry<K, V> last;\n\n        public EntryIterator() {\n            moveToNextSegment();\n        }\n\n        @Override\n        public boolean hasNext() {\n            getNextIfNecessary();\n            return (this.next != null);\n        }\n\n        @Override\n        public Entry<K, V> next() {\n            getNextIfNecessary();\n            if (this.next == null) {\n                throw new NoSuchElementException();\n            }\n            this.last = this.next;\n            this.next = null;\n            return this.last;\n        }\n\n        private void getNextIfNecessary() {\n            while (this.next == null) {\n                moveToNextReference();\n                if (this.reference == null) {\n                    return;\n                }\n                this.next = this.reference.get();\n            }\n        }\n\n        private void moveToNextReference() {\n            if (this.reference != null) {\n                this.reference = this.reference.getNext();\n            }\n            while (this.reference == null && this.references != null) {\n                if (this.referenceIndex >= this.references.length) {\n                    moveToNextSegment();\n                    this.referenceIndex = 0;\n                } else {\n                    this.reference = this.references[this.referenceIndex];\n                    this.referenceIndex++;\n                }\n            }\n        }\n\n        private void moveToNextSegment() {\n            this.reference = null;\n            this.references = null;\n            if (this.segmentIndex < ConcurrentReferenceHashMap.this.segments.length) {\n                this.references = ConcurrentReferenceHashMap.this.segments[this.segmentIndex].references;\n                this.segmentIndex++;\n            }\n        }\n\n        @Override\n        public void remove() {\n            Assert.state(this.last != null, \"No element to remove\");\n            ConcurrentReferenceHashMap.this.remove(this.last.getKey());\n            this.last = null;\n        }\n    }\n\n\n    /**\n     * The types of restructuring that can be performed.\n     */\n    protected enum Restructure {\n\n        WHEN_NECESSARY, NEVER\n    }\n\n\n    /**\n     * Strategy class used to manage {@link Reference References}.\n     * This class can be overridden if alternative reference types need to be supported.\n     */\n    protected class ReferenceManager {\n\n        private final ReferenceQueue<Entry<K, V>> queue = new ReferenceQueue<>();\n\n        /**\n         * Factory method used to create a new {@link Reference}.\n         *\n         * @param entry the entry contained in the reference\n         * @param hash  the hash\n         * @param next  the next reference in the chain, or {@code null} if none\n         * @return a new {@link Reference}\n         */\n        public Reference<K, V> createReference(Entry<K, V> entry, int hash, @Nullable Reference<K, V> next) {\n            if (ConcurrentReferenceHashMap.this.referenceType == ReferenceType.WEAK) {\n                return new WeakEntryReference<>(entry, hash, next, this.queue);\n            }\n            return new SoftEntryReference<>(entry, hash, next, this.queue);\n        }\n\n        /**\n         * Return any reference that has been garbage collected and can be purged from the\n         * underlying structure or {@code null} if no references need purging. This\n         * method must be thread safe and ideally should not block when returning\n         * {@code null}. References should be returned once and only once.\n         *\n         * @return a reference to purge or {@code null}\n         */\n        @SuppressWarnings(\"unchecked\")\n        @Nullable\n        public Reference<K, V> pollForPurge() {\n            return (Reference<K, V>) this.queue.poll();\n        }\n    }\n\n\n    /**\n     * Internal {@link Reference} implementation for {@link SoftReference SoftReferences}.\n     */\n    private static final class SoftEntryReference<K, V> extends SoftReference<Entry<K, V>> implements Reference<K, V> {\n\n        private final int hash;\n\n        @Nullable\n        private final Reference<K, V> nextReference;\n\n        public SoftEntryReference(Entry<K, V> entry, int hash, @Nullable Reference<K, V> next,\n                                  ReferenceQueue<Entry<K, V>> queue) {\n\n            super(entry, queue);\n            this.hash = hash;\n            this.nextReference = next;\n        }\n\n        @Override\n        public int getHash() {\n            return this.hash;\n        }\n\n        @Override\n        @Nullable\n        public Reference<K, V> getNext() {\n            return this.nextReference;\n        }\n\n        @Override\n        public void release() {\n            enqueue();\n            clear();\n        }\n    }\n\n\n    /**\n     * Internal {@link Reference} implementation for {@link WeakReference WeakReferences}.\n     */\n    private static final class WeakEntryReference<K, V> extends WeakReference<Entry<K, V>> implements Reference<K, V> {\n\n        private final int hash;\n\n        @Nullable\n        private final Reference<K, V> nextReference;\n\n        public WeakEntryReference(Entry<K, V> entry, int hash, @Nullable Reference<K, V> next,\n                                  ReferenceQueue<Entry<K, V>> queue) {\n\n            super(entry, queue);\n            this.hash = hash;\n            this.nextReference = next;\n        }\n\n        @Override\n        public int getHash() {\n            return this.hash;\n        }\n\n        @Override\n        @Nullable\n        public Reference<K, V> getNext() {\n            return this.nextReference;\n        }\n\n        @Override\n        public void release() {\n            enqueue();\n            clear();\n        }\n    }\n\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/internal/util/ObjectUtils.java",
    "content": "/*\n * Copyright 2002-2021 the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.alibaba.ttl3.internal.util;\n\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This source code file is copied from spring v5.3.24:\n//\n// https://github.com/spring-projects/spring-framework/blob/v5.3.24/spring-core/src/main/java/org/springframework/util/ObjectUtils.java\n//\n// with adoption:\n// - remove unused elements\n// - adjust visible modifier and code format\n//\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\nimport edu.umd.cs.findbugs.annotations.Nullable;\n\nimport java.util.Arrays;\n\n/**\n * Miscellaneous object utility methods.\n *\n * <p>Mainly for internal use within the framework.\n *\n * <p>Thanks to Alex Ruiz for contributing several enhancements to this class!\n *\n * @author Juergen Hoeller\n * @author Keith Donald\n * @author Rod Johnson\n * @author Rob Harrop\n * @author Chris Beams\n * @author Sam Brannen\n */\nfinal class ObjectUtils {\n\n    private static final int INITIAL_HASH = 7;\n    private static final int MULTIPLIER = 31;\n\n\n    //---------------------------------------------------------------------\n    // Convenience methods for content-based equality/hash-code handling\n    //---------------------------------------------------------------------\n\n    /**\n     * Determine if the given objects are equal, returning {@code true} if\n     * both are {@code null} or {@code false} if only one is {@code null}.\n     * <p>Compares arrays with {@code Arrays.equals}, performing an equality\n     * check based on the array elements rather than the array reference.\n     *\n     * @param o1 first Object to compare\n     * @param o2 second Object to compare\n     * @return whether the given objects are equal\n     * @see Object#equals(Object)\n     * @see java.util.Arrays#equals\n     */\n    public static boolean nullSafeEquals(@Nullable Object o1, @Nullable Object o2) {\n        if (o1 == o2) {\n            return true;\n        }\n        if (o1 == null || o2 == null) {\n            return false;\n        }\n        if (o1.equals(o2)) {\n            return true;\n        }\n        if (o1.getClass().isArray() && o2.getClass().isArray()) {\n            return arrayEquals(o1, o2);\n        }\n        return false;\n    }\n\n    /**\n     * Compare the given arrays with {@code Arrays.equals}, performing an equality\n     * check based on the array elements rather than the array reference.\n     *\n     * @param o1 first array to compare\n     * @param o2 second array to compare\n     * @return whether the given objects are equal\n     * @see #nullSafeEquals(Object, Object)\n     * @see java.util.Arrays#equals\n     */\n    private static boolean arrayEquals(Object o1, Object o2) {\n        if (o1 instanceof Object[] && o2 instanceof Object[]) {\n            return Arrays.equals((Object[]) o1, (Object[]) o2);\n        }\n        if (o1 instanceof boolean[] && o2 instanceof boolean[]) {\n            return Arrays.equals((boolean[]) o1, (boolean[]) o2);\n        }\n        if (o1 instanceof byte[] && o2 instanceof byte[]) {\n            return Arrays.equals((byte[]) o1, (byte[]) o2);\n        }\n        if (o1 instanceof char[] && o2 instanceof char[]) {\n            return Arrays.equals((char[]) o1, (char[]) o2);\n        }\n        if (o1 instanceof double[] && o2 instanceof double[]) {\n            return Arrays.equals((double[]) o1, (double[]) o2);\n        }\n        if (o1 instanceof float[] && o2 instanceof float[]) {\n            return Arrays.equals((float[]) o1, (float[]) o2);\n        }\n        if (o1 instanceof int[] && o2 instanceof int[]) {\n            return Arrays.equals((int[]) o1, (int[]) o2);\n        }\n        if (o1 instanceof long[] && o2 instanceof long[]) {\n            return Arrays.equals((long[]) o1, (long[]) o2);\n        }\n        if (o1 instanceof short[] && o2 instanceof short[]) {\n            return Arrays.equals((short[]) o1, (short[]) o2);\n        }\n        return false;\n    }\n\n    /**\n     * Return as hash code for the given object; typically the value of\n     * {@code Object#hashCode()}}. If the object is an array,\n     * this method will delegate to any of the {@code nullSafeHashCode}\n     * methods for arrays in this class. If the object is {@code null},\n     * this method returns 0.\n     *\n     * @see Object#hashCode()\n     * @see #nullSafeHashCode(Object[])\n     * @see #nullSafeHashCode(boolean[])\n     * @see #nullSafeHashCode(byte[])\n     * @see #nullSafeHashCode(char[])\n     * @see #nullSafeHashCode(double[])\n     * @see #nullSafeHashCode(float[])\n     * @see #nullSafeHashCode(int[])\n     * @see #nullSafeHashCode(long[])\n     * @see #nullSafeHashCode(short[])\n     */\n    public static int nullSafeHashCode(@Nullable Object obj) {\n        if (obj == null) {\n            return 0;\n        }\n        if (obj.getClass().isArray()) {\n            if (obj instanceof Object[]) {\n                return nullSafeHashCode((Object[]) obj);\n            }\n            if (obj instanceof boolean[]) {\n                return nullSafeHashCode((boolean[]) obj);\n            }\n            if (obj instanceof byte[]) {\n                return nullSafeHashCode((byte[]) obj);\n            }\n            if (obj instanceof char[]) {\n                return nullSafeHashCode((char[]) obj);\n            }\n            if (obj instanceof double[]) {\n                return nullSafeHashCode((double[]) obj);\n            }\n            if (obj instanceof float[]) {\n                return nullSafeHashCode((float[]) obj);\n            }\n            if (obj instanceof int[]) {\n                return nullSafeHashCode((int[]) obj);\n            }\n            if (obj instanceof long[]) {\n                return nullSafeHashCode((long[]) obj);\n            }\n            if (obj instanceof short[]) {\n                return nullSafeHashCode((short[]) obj);\n            }\n        }\n        return obj.hashCode();\n    }\n\n    /**\n     * Return a hash code based on the contents of the specified array.\n     * If {@code array} is {@code null}, this method returns 0.\n     */\n    public static int nullSafeHashCode(@Nullable Object[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hash = INITIAL_HASH;\n        for (Object element : array) {\n            hash = MULTIPLIER * hash + nullSafeHashCode(element);\n        }\n        return hash;\n    }\n\n    /**\n     * Return a hash code based on the contents of the specified array.\n     * If {@code array} is {@code null}, this method returns 0.\n     */\n    public static int nullSafeHashCode(@Nullable boolean[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hash = INITIAL_HASH;\n        for (boolean element : array) {\n            hash = MULTIPLIER * hash + Boolean.hashCode(element);\n        }\n        return hash;\n    }\n\n    /**\n     * Return a hash code based on the contents of the specified array.\n     * If {@code array} is {@code null}, this method returns 0.\n     */\n    public static int nullSafeHashCode(@Nullable byte[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hash = INITIAL_HASH;\n        for (byte element : array) {\n            hash = MULTIPLIER * hash + element;\n        }\n        return hash;\n    }\n\n    /**\n     * Return a hash code based on the contents of the specified array.\n     * If {@code array} is {@code null}, this method returns 0.\n     */\n    public static int nullSafeHashCode(@Nullable char[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hash = INITIAL_HASH;\n        for (char element : array) {\n            hash = MULTIPLIER * hash + element;\n        }\n        return hash;\n    }\n\n    /**\n     * Return a hash code based on the contents of the specified array.\n     * If {@code array} is {@code null}, this method returns 0.\n     */\n    public static int nullSafeHashCode(@Nullable double[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hash = INITIAL_HASH;\n        for (double element : array) {\n            hash = MULTIPLIER * hash + Double.hashCode(element);\n        }\n        return hash;\n    }\n\n    /**\n     * Return a hash code based on the contents of the specified array.\n     * If {@code array} is {@code null}, this method returns 0.\n     */\n    public static int nullSafeHashCode(@Nullable float[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hash = INITIAL_HASH;\n        for (float element : array) {\n            hash = MULTIPLIER * hash + Float.hashCode(element);\n        }\n        return hash;\n    }\n\n    /**\n     * Return a hash code based on the contents of the specified array.\n     * If {@code array} is {@code null}, this method returns 0.\n     */\n    public static int nullSafeHashCode(@Nullable int[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hash = INITIAL_HASH;\n        for (int element : array) {\n            hash = MULTIPLIER * hash + element;\n        }\n        return hash;\n    }\n\n    /**\n     * Return a hash code based on the contents of the specified array.\n     * If {@code array} is {@code null}, this method returns 0.\n     */\n    public static int nullSafeHashCode(@Nullable long[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hash = INITIAL_HASH;\n        for (long element : array) {\n            hash = MULTIPLIER * hash + Long.hashCode(element);\n        }\n        return hash;\n    }\n\n    /**\n     * Return a hash code based on the contents of the specified array.\n     * If {@code array} is {@code null}, this method returns 0.\n     */\n    public static int nullSafeHashCode(@Nullable short[] array) {\n        if (array == null) {\n            return 0;\n        }\n        int hash = INITIAL_HASH;\n        for (short element : array) {\n            hash = MULTIPLIER * hash + element;\n        }\n        return hash;\n    }\n\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/internal/util/Utils.java",
    "content": "package com.alibaba.ttl3.internal.util;\n\nimport org.jetbrains.annotations.ApiStatus;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// Most source code of this file is copied from spring v5.3.24:\n//\n// https://github.com/spring-projects/spring-framework/blob/v5.3.24/spring-core/src/main/java/org/springframework/util/CollectionUtils.java\n//\n// with adoption:\n// - adjust visible modifier and code format\n//\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n@ApiStatus.Internal\npublic final class Utils {\n    /**\n     * Default load factor for {@link HashMap}/{@link LinkedHashMap} variants.\n     *\n     * @see #newHashMap(int)\n     */\n    private static final float DEFAULT_LOAD_FACTOR = 0.75f;\n\n    /**\n     * Instantiate a new {@link HashMap} with an initial capacity\n     * that can accommodate the specified number of elements without\n     * any immediate resize/rehash operations to be expected.\n     * <p>This differs from the regular {@link HashMap} constructor\n     * which takes an initial capacity relative to a load factor\n     * but is effectively aligned with the JDK's\n     * {@link java.util.concurrent.ConcurrentHashMap#ConcurrentHashMap(int)}.\n     *\n     * @param expectedSize the expected number of elements (with a corresponding\n     *                     capacity to be derived so that no resize/rehash operations are needed)\n     */\n    public static <K, V> HashMap<K, V> newHashMap(int expectedSize) {\n        return new HashMap<>(computeMapInitialCapacity(expectedSize), DEFAULT_LOAD_FACTOR);\n    }\n\n    /**\n     * Instantiate a new {@code ConcurrentWeakHashMap} with an initial capacity\n     * that can accommodate the specified number of elements without\n     * any immediate resize/rehash operations to be expected.\n     *\n     * @param expectedSize the expected number of elements (with a corresponding\n     *                     capacity to be derived so that no resize/rehash operations are needed)\n     */\n    public static <K, V> ConcurrentMap<K, V> newConcurrentWeakHashMap(int expectedSize) {\n        return new ConcurrentReferenceHashMap<>(computeMapInitialCapacity(expectedSize), ConcurrentReferenceHashMap.ReferenceType.WEAK);\n    }\n\n    private static int computeMapInitialCapacity(int expectedSize) {\n        return (int) Math.ceil(expectedSize / (double) DEFAULT_LOAD_FACTOR);\n    }\n\n    /**\n     * @see <a href=\"https://scala-lang.org/api/3.1.3/scala/util/control/NonFatal$.html\"><code>scala.util.control</code></a>\n     * @see <a href=\"https://github.com/scala/scala/blob/v2.13.9/src/library/scala/util/control/NonFatal.scala#L35-L43\">github.com/scala/scala/blob/v2.13.9/src/library/scala/util/control/NonFatal.scala</a>\n     */\n    public static void propagateIfFatal(@Nullable Throwable throwable) {\n        if (throwable == null) return;\n\n        if (throwable instanceof VirtualMachineError\n                || throwable instanceof ThreadDeath\n                || throwable instanceof InterruptedException\n                || throwable instanceof LinkageError) {\n            sneakyThrow(throwable);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static <E extends Throwable> void sneakyThrow(Throwable e) throws E {\n        throw (E) e;\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/package-info.java",
    "content": "/**\n * TTL API.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.TransmittableThreadLocal\n * @see com.alibaba.ttl3.TtlRunnable\n * @see com.alibaba.ttl3.TtlCallable\n * @see com.alibaba.ttl3.TtlWrappers\n */\npackage com.alibaba.ttl3;\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/spi/TtlAttachments.java",
    "content": "package com.alibaba.ttl3.spi;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\n/**\n * The TTL attachments for TTL tasks,\n * eg: {@link com.alibaba.ttl3.TtlRunnable}, {@link com.alibaba.ttl3.TtlCallable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\npublic interface TtlAttachments extends TtlEnhanced {\n    /**\n     * set the TTL attachments for TTL tasks\n     *\n     * @param key   attachment key\n     * @param value attachment value\n     */\n    void setTtlAttachment(@NonNull String key, Object value);\n\n    /**\n     * get the TTL attachment for TTL tasks\n     *\n     * @param key attachment key\n     */\n    <T> T getTtlAttachment(@NonNull String key);\n\n    /**\n     * The attachment key of TTL task, weather this task is a auto wrapper task.\n     * <p>\n     * so the value of this attachment is a {@code boolean}.\n     */\n    String KEY_IS_AUTO_WRAPPER = \"ttl.is.auto.wrapper\";\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/spi/TtlAttachmentsDelegate.java",
    "content": "package com.alibaba.ttl3.spi;\n\nimport com.alibaba.ttl3.TtlWrappers;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * {@link TtlAttachments} delegate/implementation.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.TtlRunnable\n * @see com.alibaba.ttl3.TtlCallable\n */\npublic class TtlAttachmentsDelegate implements TtlAttachments {\n    private final ConcurrentMap<String, Object> attachments = new ConcurrentHashMap<>();\n\n    @Override\n    public void setTtlAttachment(@NonNull String key, Object value) {\n        attachments.put(key, value);\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> T getTtlAttachment(@NonNull String key) {\n        return (T) attachments.get(key);\n    }\n\n    // ======== AutoWrapper Util Methods ========\n\n    /**\n     * @see TtlAttachments#KEY_IS_AUTO_WRAPPER\n     */\n    public static boolean isAutoWrapper(@Nullable Object ttlAttachments) {\n        if (!(ttlAttachments instanceof TtlAttachments)) return false;\n\n        final Boolean value = ((TtlAttachments) ttlAttachments).getTtlAttachment(KEY_IS_AUTO_WRAPPER);\n        if (value == null) return false;\n\n        return value;\n    }\n\n    /**\n     * @see TtlAttachments#KEY_IS_AUTO_WRAPPER\n     */\n    public static void setAutoWrapperAttachment(@Nullable Object ttlAttachment) {\n        if (!(ttlAttachment instanceof TtlAttachments)) return;\n\n        ((TtlAttachments) ttlAttachment).setTtlAttachment(TtlAttachments.KEY_IS_AUTO_WRAPPER, true);\n    }\n\n    /**\n     * @see TtlAttachments#KEY_IS_AUTO_WRAPPER\n     */\n    @Nullable\n    public static <T> T unwrapIfIsAutoWrapper(@Nullable T obj) {\n        if (isAutoWrapper(obj)) return TtlWrappers.unwrap(obj);\n        else return obj;\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/spi/TtlEnhanced.java",
    "content": "package com.alibaba.ttl3.spi;\n\n/**\n * a Ttl marker/tag interface, for ttl enhanced class, for example {@code TTL wrapper}\n * like {@link com.alibaba.ttl3.TtlRunnable}, {@link com.alibaba.ttl3.TtlCallable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.TtlRunnable\n * @see com.alibaba.ttl3.TtlCallable\n * @see com.alibaba.ttl3.TtlRecursiveAction\n * @see com.alibaba.ttl3.TtlRecursiveTask\n * @see TtlAttachments\n */\npublic interface TtlEnhanced {\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/spi/TtlWrapper.java",
    "content": "package com.alibaba.ttl3.spi;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\n/**\n * Ttl Wrapper interface.\n * <p>\n * Used to mark wrapper types, for example:\n * <ul>\n *     <li>{@link com.alibaba.ttl3.TtlRunnable TtlRunnable}s, {@link com.alibaba.ttl3.TtlCallable TtlCallable}s\n *     <li>{@code TtlWrappers} created by util methods {@code wrap*()} of class\n *         {@link com.alibaba.ttl3.TtlWrappers TtlWrappers},\n *         e.g. {@link com.alibaba.ttl3.TtlWrappers#wrapSupplier(java.util.function.Supplier) wrapSupplier}\n *     <li>{@code TtlExecutors} created by util methods {@code get*()} of class\n *         {@link com.alibaba.ttl3.executor.TtlExecutors TtlExecutors},\n *         e.g. {@link com.alibaba.ttl3.executor.TtlExecutors#getTtlExecutorService(java.util.concurrent.ExecutorService) getTtlExecutorService}\n *     <li>{@code DisableInheritableThreadFactories} created by util method\n *         {@link com.alibaba.ttl3.executor.TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory) getDisableInheritableThreadFactory}\n * </ul>\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.TtlWrappers#unwrap\n * @see com.alibaba.ttl3.TtlRunnable\n * @see com.alibaba.ttl3.TtlCallable\n * @see com.alibaba.ttl3.TtlWrappers\n * @see com.alibaba.ttl3.executor.TtlExecutors\n */\npublic interface TtlWrapper<T> extends TtlEnhanced {\n    /**\n     * unwrap {@link TtlWrapper} to the original/underneath one.\n     *\n     * @see com.alibaba.ttl3.TtlWrappers#unwrap\n     */\n    @NonNull\n    T unwrap();\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/spi/package-info.java",
    "content": "/**\n * TTL SPI contains internal types for {@code TTL} developer to integrate with {@code TTL};\n * You will <b><i>never</i></b> need use this package in the <i>biz/application codes</i>.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.spi.TtlEnhanced\n * @see com.alibaba.ttl3.spi.TtlWrapper\n * @see com.alibaba.ttl3.spi.TtlAttachments\n */\npackage com.alibaba.ttl3.spi;\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/transmitter/ThreadLocalTransmitRegistry.java",
    "content": "package com.alibaba.ttl3.transmitter;\n\nimport com.alibaba.ttl3.TransmittableThreadLocal;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.WeakHashMap;\nimport java.util.function.UnaryOperator;\nimport java.util.logging.Logger;\n\nimport static com.alibaba.ttl3.internal.util.Utils.newHashMap;\n\n/**\n * {@code ThreadLocalTransmitRegistry}, {@code ThreadLocal} transmit integration.\n * <p>\n * If you can not rewrite the existed code which use {@link ThreadLocal} to {@link TransmittableThreadLocal},\n * register the {@link ThreadLocal} instances via the methods\n * {@link ThreadLocalTransmitRegistry#registerThreadLocal(ThreadLocal, UnaryOperator)}\n * to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.\n * <p>\n * {@code ThreadLocalTransmitRegistry} implement a {@link Transmittee} internally,\n * and register the {@link Transmittee} by {@link TransmitteeRegistry#registerTransmittee(Transmittee)}\n * to transmit all registered {@link ThreadLocal} instances.\n *\n * <p>\n * Below is the example code:\n *\n * <pre>{@code\n * // the value of this ThreadLocal instance will be transmitted after registered\n * ThreadLocalTransmitRegistry.registerThreadLocal(aThreadLocal, generator);\n *\n * // Then the value of this ThreadLocal instance will not be transmitted after unregistered\n * ThreadLocalTransmitRegistry.unregisterThreadLocal(aThreadLocal);}</pre>\n * <p>\n * The fields stored the {@code ThreadLocal} instances are generally {@code private static},\n * so the {@code ThreadLocal} instances need be got by reflection, for example:\n *\n * <pre>\n * Field field = TheClassStoredThreadLocal.class.getDeclaredField(staticFieldName);\n * field.setAccessible(true);\n * {@code @SuppressWarnings(\"unchecked\")}\n * {@code ThreadLocal<T>} threadLocal = {@code (ThreadLocal<T>)} field.get(null);</pre>\n *\n * <B><I>Caution:</I></B><br>\n * If the registered {@link ThreadLocal} instance is not {@link InheritableThreadLocal},\n * the instance can NOT <B><I>{@code inherit}</I></B> value from parent thread(aka. the <b>inheritable</b> ability)!\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see TransmitteeRegistry#registerTransmittee(Transmittee)\n */\npublic final class ThreadLocalTransmitRegistry {\n    private static final Logger logger = Logger.getLogger(ThreadLocalTransmitRegistry.class.getName());\n\n    private static volatile WeakHashMap<ThreadLocal<Object>, UnaryOperator<Object>> threadLocalHolder = new WeakHashMap<>();\n\n    private static final Object threadLocalHolderUpdateLock = new Object();\n\n    /**\n     * Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances\n     * to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.\n     * <p>\n     * If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}.\n     * since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability,\n     * it is unnecessary to register a {@link TransmittableThreadLocal} instance.\n     * <p>\n     * <B><I>Caution:</I></B><br>\n     * If the registered {@link ThreadLocal} instance is not {@link InheritableThreadLocal},\n     * the instance can NOT <B><I>{@code inherit}</I></B> value from parent thread(aka. the <b>inheritable</b> ability)!\n     *\n     * @param threadLocal the {@link ThreadLocal} instance that to enhance the <b>Transmittable</b> ability\n     * @param generator   the value generator of type {@code UnaryOperator}\n     * @return {@code true} if register the {@link ThreadLocal} instance and set {@code generator}, otherwise {@code false}\n     * @see #registerThreadLocal(ThreadLocal, UnaryOperator, boolean)\n     */\n    public static <T> boolean registerThreadLocal(@NonNull ThreadLocal<T> threadLocal, @NonNull UnaryOperator<T> generator) {\n        return registerThreadLocal(threadLocal, generator, false);\n    }\n\n    /**\n     * Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances\n     * to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.\n     * <p>\n     * If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}.\n     * since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability,\n     * it is unnecessary to register a {@link TransmittableThreadLocal} instance.\n     * <p>\n     * <B><I>Caution:</I></B><br>\n     * If the registered {@link ThreadLocal} instance is not {@link InheritableThreadLocal},\n     * the instance can NOT <B><I>{@code inherit}</I></B> value from parent thread(aka. the <b>inheritable</b> ability)!\n     *\n     * @param threadLocal the {@link ThreadLocal} instance that to enhance the <b>Transmittable</b> ability\n     * @param generator   the value generator of type {@code UnaryOperator}\n     * @param force       if {@code true}, update {@code generator} to {@link ThreadLocal} instance\n     *                    when a {@link ThreadLocal} instance is already registered; otherwise, ignore.\n     * @return {@code true} if register the {@link ThreadLocal} instance and set {@code generator}, otherwise {@code false}\n     * @see #registerThreadLocal(ThreadLocal, UnaryOperator)\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> boolean registerThreadLocal(@NonNull ThreadLocal<T> threadLocal, @NonNull UnaryOperator<T> generator, boolean force) {\n        if (threadLocal instanceof TransmittableThreadLocal) {\n            logger.warning(\"register a TransmittableThreadLocal instance, this is unnecessary!\");\n            return true;\n        }\n\n        synchronized (threadLocalHolderUpdateLock) {\n            if (!force && threadLocalHolder.containsKey(threadLocal)) return false;\n\n            WeakHashMap<ThreadLocal<Object>, UnaryOperator<Object>> newHolder = new WeakHashMap<>(threadLocalHolder);\n            newHolder.put((ThreadLocal<Object>) threadLocal, (UnaryOperator<Object>) generator);\n            threadLocalHolder = newHolder;\n            return true;\n        }\n    }\n\n    /**\n     * Unregister the {@link ThreadLocal} instances\n     * to remove the <b>Transmittable</b> ability for the {@link ThreadLocal} instances.\n     * <p>\n     * If the {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}.\n     *\n     * @see #registerThreadLocal(ThreadLocal, UnaryOperator)\n     */\n    public static <T> boolean unregisterThreadLocal(@NonNull ThreadLocal<T> threadLocal) {\n        if (threadLocal instanceof TransmittableThreadLocal) {\n            logger.warning(\"unregister a TransmittableThreadLocal instance, this is unnecessary!\");\n            return true;\n        }\n\n        synchronized (threadLocalHolderUpdateLock) {\n            if (!threadLocalHolder.containsKey(threadLocal)) return false;\n\n            WeakHashMap<ThreadLocal<Object>, UnaryOperator<Object>> newHolder = new WeakHashMap<>(threadLocalHolder);\n            newHolder.remove(threadLocal);\n            threadLocalHolder = newHolder;\n            return true;\n        }\n    }\n\n\n    private static class ThreadLocalTransmittee implements Transmittee<HashMap<ThreadLocal<Object>, Object>, HashMap<ThreadLocal<Object>, Object>> {\n        private static final Object threadLocalClearMark = new Object();\n\n        @NonNull\n        @Override\n        public HashMap<ThreadLocal<Object>, Object> capture() {\n            final HashMap<ThreadLocal<Object>, Object> threadLocal2Value = newHashMap(threadLocalHolder.size());\n            for (Map.Entry<ThreadLocal<Object>, UnaryOperator<Object>> entry : threadLocalHolder.entrySet()) {\n                final ThreadLocal<Object> threadLocal = entry.getKey();\n                final UnaryOperator<Object> generator = entry.getValue();\n\n                threadLocal2Value.put(threadLocal, generator.apply(threadLocal.get()));\n            }\n            return threadLocal2Value;\n        }\n\n        @NonNull\n        @Override\n        public HashMap<ThreadLocal<Object>, Object> replay(@NonNull HashMap<ThreadLocal<Object>, Object> captured) {\n            final HashMap<ThreadLocal<Object>, Object> backup = newHashMap(captured.size());\n\n            for (Map.Entry<ThreadLocal<Object>, Object> entry : captured.entrySet()) {\n                final ThreadLocal<Object> threadLocal = entry.getKey();\n                backup.put(threadLocal, threadLocal.get());\n\n                final Object value = entry.getValue();\n                if (value == threadLocalClearMark) threadLocal.remove();\n                else threadLocal.set(value);\n            }\n\n            return backup;\n        }\n\n        @NonNull\n        @Override\n        public HashMap<ThreadLocal<Object>, Object> clear() {\n            final HashMap<ThreadLocal<Object>, Object> threadLocal2Value = newHashMap(threadLocalHolder.size());\n\n            for (Map.Entry<ThreadLocal<Object>, UnaryOperator<Object>> entry : threadLocalHolder.entrySet()) {\n                final ThreadLocal<Object> threadLocal = entry.getKey();\n                threadLocal2Value.put(threadLocal, threadLocalClearMark);\n            }\n\n            return replay(threadLocal2Value);\n        }\n\n        @Override\n        public void restore(@NonNull HashMap<ThreadLocal<Object>, Object> backup) {\n            for (Map.Entry<ThreadLocal<Object>, Object> entry : backup.entrySet()) {\n                final ThreadLocal<Object> threadLocal = entry.getKey();\n                threadLocal.set(entry.getValue());\n            }\n        }\n    }\n\n    private static final ThreadLocalTransmittee threadLocalTransmittee = new ThreadLocalTransmittee();\n\n    static {\n        TransmitteeRegistry.registerTransmittee(threadLocalTransmittee);\n    }\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private ThreadLocalTransmitRegistry() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/transmitter/Transmittee.java",
    "content": "package com.alibaba.ttl3.transmitter;\n\nimport com.alibaba.crr.Transmittable;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\n/**\n * The transmittee is the extension point to transmit {@code ThreadLocal}s\n * ({@code JDK} {@link ThreadLocal}, {@code FastThreadLocal} of {@code Netty}, etc.).\n * <p>\n * {@code ThreadLocal} transmittance is registered\n * by {@link TransmitteeRegistry#registerTransmittee(Transmittee)} method.\n * <p>\n * Transmittance process is represented by methods {@link #capture()} =&gt;\n * {@link #replay(Object)} =&gt; {@link #restore(Object)} (aka {@code CRR} operations).\n *\n * @param <C> the transmittee capture data type\n * @param <B> the transmittee backup data type\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see TransmitteeRegistry#registerTransmittee(Transmittee)\n * @see TransmitteeRegistry#unregisterTransmittee(Transmittee)\n */\npublic interface Transmittee<C, B> extends Transmittable<C, B> {\n    /**\n     * Capture.\n     * <p>\n     * <B><I>NOTE:</I></B>\n     * <ul>\n     * <li>do NOT return {@code null}.</li>\n     * <li>do NOT throw any exceptions, just ignored.</li>\n     * </ul>\n     *\n     * @return the capture data of transmittee\n     */\n    @NonNull\n    C capture();\n\n    /**\n     * Replay.\n     * <p>\n     * <B><I>NOTE:</I></B>\n     * <ul>\n     * <li>do NOT return {@code null}.</li>\n     * <li>do NOT throw any exceptions, just ignored.</li>\n     * </ul>\n     *\n     * @param captured the capture data of transmittee, the return value of method {@link #capture()}\n     * @return the backup data of transmittee\n     */\n    @NonNull\n    B replay(@NonNull C captured);\n\n    /**\n     * Clear.\n     * <p>\n     * <B><I>NOTE:</I></B>\n     * <ul>\n     * <li>do NOT return {@code null}.</li>\n     * <li>do NOT throw any exceptions, just ignored.</li>\n     * </ul>\n     * <p>\n     * Semantically, the code {@code `B backup = clear();`} is same as {@code `B backup = replay(EMPTY_CAPTURE);`}.\n     * <p>\n     * The reason for providing this method is:\n     * <ol>\n     * <li>lead to more readable code</li>\n     * <li>need not provide the constant {@code EMPTY_CAPTURE}.</li>\n     * </ol>\n     *\n     * @return the backup data of transmittee\n     */\n    @NonNull\n    B clear();\n\n    /**\n     * Restore.\n     * <p>\n     * <B><I>NOTE:</I></B><br>\n     * do NOT throw any exceptions, just ignored.\n     *\n     * @param backup the backup data of transmittee, the return value of methods {@link #replay(Object)} or {@link #clear()}\n     * @see #replay(Object)\n     * @see #clear()\n     */\n    void restore(@NonNull B backup);\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/transmitter/TransmitteeRegistry.java",
    "content": "package com.alibaba.ttl3.transmitter;\n\nimport com.alibaba.ttl3.TransmittableThreadLocal;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\n/**\n * Transmittee(aka {@code ThreadLocal}) Integration,\n * {@link TransmittableThreadLocal} and {@code JDK} {@link ThreadLocal}\n * (via {@link ThreadLocalTransmitRegistry}) have been builtin integrated.\n *\n * <h2>About {@code JDK} {@link ThreadLocal} Integration</h2>\n * <p>\n * If you can not rewrite the existed code which use {@code JDK} {@link ThreadLocal}\n * to {@link TransmittableThreadLocal}, register the {@link ThreadLocal} instances\n * via {@link ThreadLocalTransmitRegistry}\n * to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.\n *\n * <h2>Other {@code ThreadLocal} Integration</h2>\n * <p>\n * For other {@code ThreadLocal}s integration(e.g. {@code FastThreadLocal} of {@code Netty}),\n * you can implement your own {@code XxxThreadLocalRegistry}\n * (e.g. {@code FastThreadLocalRegistry}) like {@link ThreadLocalTransmitRegistry}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see Transmittee\n * @see ThreadLocalTransmitRegistry\n */\npublic final class TransmitteeRegistry {\n    /**\n     * Register the transmittee({@code CRR}), the extension point for other {@code ThreadLocal}.\n     *\n     * @param <C> the transmittee capture data type\n     * @param <B> the transmittee backup data type\n     * @return true if the input transmittee is not registered\n     * @see #unregisterTransmittee(Transmittee)\n     */\n    public static <C, B> boolean registerTransmittee(@NonNull Transmittee<C, B> transmittee) {\n        return Transmitter.compositeTransmittable.registerTransmittable(transmittee);\n    }\n\n    /**\n     * Unregister the transmittee({@code CRR}), the extension point for other {@code ThreadLocal}.\n     *\n     * @param <C> the transmittee capture data type\n     * @param <B> the transmittee backup data type\n     * @return true if the input transmittee is registered\n     * @see #registerTransmittee(Transmittee)\n     */\n    public static <C, B> boolean unregisterTransmittee(@NonNull Transmittee<C, B> transmittee) {\n        return Transmitter.compositeTransmittable.unregisterTransmittable(transmittee);\n    }\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TransmitteeRegistry() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/transmitter/Transmitter.java",
    "content": "package com.alibaba.ttl3.transmitter;\n\nimport com.alibaba.crr.TransmitCallback;\nimport com.alibaba.crr.composite.Backup;\nimport com.alibaba.crr.composite.Capture;\nimport com.alibaba.crr.composite.CompositeTransmittable;\nimport com.alibaba.crr.composite.CompositeTransmitCallback;\nimport com.alibaba.ttl3.TransmittableThreadLocal;\nimport com.alibaba.ttl3.TtlCallable;\nimport com.alibaba.ttl3.TtlRunnable;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.util.concurrent.Callable;\nimport java.util.function.Supplier;\n\n/**\n * {@link Transmitter} transmit all {@link TransmittableThreadLocal}\n * and other registered {@link ThreadLocal} values of the current thread to other thread.\n * <p>\n * Transmittance is completed by static methods {@link #capture()} =&gt;\n * {@link #replay(Capture)} =&gt; {@link #restore(Backup)} (aka {@code CRR} operations).\n * {@code JDK} {@link ThreadLocal} instances can be registered via {@link ThreadLocalTransmitRegistry}.\n * <p>\n * {@link Transmitter Transmitter} is <b><i>internal</i></b> manipulation api\n * for <b><i>framework/middleware integration</i></b>;\n * In general, you will <b><i>never</i></b> use it in the <i>biz/application codes</i>!\n *\n * <h2>Executor framework/middleware integration to TTL transmittance</h2>\n * Below is the example code:\n *\n * <pre>{@code\n * ///////////////////////////////////////////////////////////////////////////\n * // in thread A, capture all TransmittableThreadLocal values of thread A\n * ///////////////////////////////////////////////////////////////////////////\n *\n * Capture captured = Transmitter.capture(); // (1)\n *\n * ///////////////////////////////////////////////////////////////////////////\n * // in thread B\n * ///////////////////////////////////////////////////////////////////////////\n *\n * // replay all TransmittableThreadLocal values from thread A\n * Backup backup = Transmitter.replay(captured); // (2)\n * try {\n *     // your biz logic, run with the TransmittableThreadLocal values of thread B\n *     System.out.println(\"Hello\");\n *     // ...\n *     return \"World\";\n * } finally {\n *     // restore the TransmittableThreadLocal of thread B when replay\n *     Transmitter.restore(backup); // (3)\n * }}</pre>\n * <p>\n * see the implementation code of {@link TtlRunnable} and {@link TtlCallable}\n * for more actual code samples.\n * <p>\n * Of course, {@link #replay(Capture)} and {@link #restore(Backup)} operations\n * can be simplified by util methods {@link #runCallableWithCaptured(Capture, Callable)}\n * or {@link #runSupplierWithCaptured(Capture, Supplier)}\n * and the adorable {@code Java 8 lambda syntax}.\n * <p>\n * Below is the example code:\n *\n * <pre>{@code\n * ///////////////////////////////////////////////////////////////////////////\n * // in thread A, capture all TransmittableThreadLocal values of thread A\n * ///////////////////////////////////////////////////////////////////////////\n *\n * Capture captured = Transmitter.capture(); // (1)\n *\n * ///////////////////////////////////////////////////////////////////////////\n * // in thread B\n * ///////////////////////////////////////////////////////////////////////////\n *\n * String result = runSupplierWithCaptured(captured, () -> {\n *      // your biz logic, run with the TransmittableThreadLocal values of thread A\n *      System.out.println(\"Hello\");\n *      ...\n *      return \"World\";\n * }); // (2) + (3)}</pre>\n * <p>\n * The reason of providing 2 util methods is the different {@code throws Exception} type\n * to satisfy your biz logic({@code lambda}):\n * <ol>\n * <li>{@link #runCallableWithCaptured(Capture, Callable)}: {@code throws Exception}</li>\n * <li>{@link #runSupplierWithCaptured(Capture, Supplier)}: No {@code throws}</li>\n * </ol>\n * <p>\n * If you need the different {@code throws Exception} type,\n * you can define your own util method alike for function interface({@code lambda})\n * with your own {@code throws Exception} type.\n *\n * <h2>Other ThreadLocal Integration</h2>\n * <p>\n * If you can not rewrite the existed code which use {@code JDK} {@link ThreadLocal}\n * to {@link TransmittableThreadLocal}, register the {@link ThreadLocal} instances via method\n * {@link ThreadLocalTransmitRegistry#registerThreadLocal(ThreadLocal, java.util.function.UnaryOperator) ThreadLocalTransmitRegistry#registerThreadLocal}\n * to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.\n * <p>\n * For other {@code ThreadLocal}s integration(e.g. {@code FastThreadLocal} of {@code Netty}),\n * you can implement your own {@code XxxThreadLocalRegistry}\n * (e.g. {@code FastThreadLocalRegistry}) like {@link ThreadLocalTransmitRegistry}.\n *\n * @author Yang Fang (snoop dot fy at gmail dot com)\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see TtlRunnable\n * @see TtlCallable\n * @see TransmitteeRegistry\n */\npublic final class Transmitter {\n    private static final CompositeTransmitCallback compositeCallback = new CompositeTransmitCallback();\n\n    static final CompositeTransmittable compositeTransmittable = new CompositeTransmittable(compositeCallback);\n\n    /**\n     * Capture all {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values in the current thread.\n     *\n     * @return the captured {@link TransmittableThreadLocal} values\n     */\n    @NonNull\n    public static Capture capture() {\n        return compositeTransmittable.capture();\n    }\n\n    /**\n     * Replay the captured {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values from {@link #capture()},\n     * and return the backup {@link TransmittableThreadLocal} values in the current thread before replay.\n     *\n     * @param captured captured {@link TransmittableThreadLocal} values from other thread from {@link #capture()}\n     * @return the backup {@link TransmittableThreadLocal} values before replay\n     * @see #capture()\n     */\n    @NonNull\n    public static Backup replay(@NonNull Capture captured) {\n        return compositeTransmittable.replay(captured);\n    }\n\n    /**\n     * Clear all {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values in the current thread,\n     * and return the backup {@link TransmittableThreadLocal} values in the current thread before clear.\n     * <p>\n     * Semantically, the code {@code `Backup backup = clear();`} is same as {@code `Backup backup = replay(EMPTY_CAPTURE);`}.\n     * <p>\n     * The reason for providing this method is:\n     *\n     * <ol>\n     * <li>lead to more readable code</li>\n     * <li>need not provide the constant {@code EMPTY_CAPTURE}.</li>\n     * </ol>\n     *\n     * @return the backup {@link TransmittableThreadLocal} values before clear\n     * @see #replay(Capture)\n     */\n    @NonNull\n    public static Backup clear() {\n        return compositeTransmittable.clear();\n    }\n\n    /**\n     * Restore the backup {@link TransmittableThreadLocal} and\n     * registered {@link ThreadLocal} values from {@link #replay(Capture)}/{@link #clear()}.\n     *\n     * @param backup the backup {@link TransmittableThreadLocal} values from {@link #replay(Capture)}/{@link #clear()}\n     * @see #replay(Capture)\n     * @see #clear()\n     */\n    public static void restore(@NonNull Backup backup) {\n        compositeTransmittable.restore(backup);\n    }\n\n    /**\n     * Util method for simplifying {@link #replay(Capture)} and {@link #restore(Backup)} operations.\n     *\n     * @param captured captured {@link TransmittableThreadLocal} values from other thread from {@link #capture()}\n     * @param bizLogic biz logic\n     * @param <R>      the return type of biz logic\n     * @return the return value of biz logic\n     * @see #capture()\n     * @see #replay(Capture)\n     * @see #restore(Backup)\n     */\n    public static <R> R runSupplierWithCaptured(@NonNull Capture captured, @NonNull Supplier<R> bizLogic) {\n        final Backup backup = replay(captured);\n        try {\n            return bizLogic.get();\n        } finally {\n            restore(backup);\n        }\n    }\n\n    /**\n     * Util method for simplifying {@link #clear()} and {@link #restore(Backup)} operations.\n     *\n     * @param bizLogic biz logic\n     * @param <R>      the return type of biz logic\n     * @return the return value of biz logic\n     * @see #clear()\n     * @see #restore(Backup)\n     */\n    public static <R> R runSupplierWithClear(@NonNull Supplier<R> bizLogic) {\n        final Backup backup = clear();\n        try {\n            return bizLogic.get();\n        } finally {\n            restore(backup);\n        }\n    }\n\n    /**\n     * Util method for simplifying {@link #replay(Capture)} and {@link #restore(Backup)} operations.\n     *\n     * @param captured captured {@link TransmittableThreadLocal} values from other thread from {@link #capture()}\n     * @param bizLogic biz logic\n     * @param <R>      the return type of biz logic\n     * @return the return value of biz logic\n     * @throws Exception the exception threw by biz logic\n     * @see #capture()\n     * @see #replay(Capture)\n     * @see #restore(Backup)\n     */\n    @SuppressFBWarnings(\"THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION\")\n    public static <R> R runCallableWithCaptured(@NonNull Capture captured, @NonNull Callable<R> bizLogic) throws Exception {\n        final Backup backup = replay(captured);\n        try {\n            return bizLogic.call();\n        } finally {\n            restore(backup);\n        }\n    }\n\n    /**\n     * Util method for simplifying {@link #clear()} and {@link #restore(Backup)} operations.\n     *\n     * @param bizLogic biz logic\n     * @param <R>      the return type of biz logic\n     * @return the return value of biz logic\n     * @throws Exception the exception threw by biz logic\n     * @see #clear()\n     * @see #restore(Backup)\n     */\n    @SuppressFBWarnings(\"THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION\")\n    public static <R> R runCallableWithClear(@NonNull Callable<R> bizLogic) throws Exception {\n        final Backup backup = clear();\n        try {\n            return bizLogic.call();\n        } finally {\n            restore(backup);\n        }\n    }\n\n    /**\n     * Register the {@link TransmitCallback}.\n     *\n     * @return true if the input callback is not registered\n     * @see #unregisterCallback(TransmitCallback)\n     */\n    public static boolean registerCallback(@NonNull TransmitCallback callback) {\n        return compositeCallback.registerCallback(callback);\n    }\n\n    /**\n     * Unregister the {@link TransmitCallback}.\n     *\n     * @return true if the input callback is registered\n     * @see #registerCallback(TransmitCallback)\n     */\n    public static boolean unregisterCallback(@NonNull TransmitCallback callback) {\n        return compositeCallback.unregisterCallback(callback);\n    }\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private Transmitter() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/main/java/com/alibaba/ttl3/transmitter/package-info.java",
    "content": "/**\n * The base(under layer) API for {@code TTL} developer to integrate with {@code TTL};\n * You will <b><i>never</i></b> use this package in the <i>biz/application codes</i>.\n * <p>\n * Provide:\n *\n * <ul>\n *   <li>Integration entrance({@link com.alibaba.ttl3.transmitter.Transmitter})\n *       for executors.</li>\n *   <li>Extension point({@link com.alibaba.ttl3.transmitter.TransmitteeRegistry}\n *       for other {@code ThreadLocal}s.</li>\n * </ul>\n * <p>\n * {@code JDK} {@link java.lang.ThreadLocal} is builtin supported\n * by {@link com.alibaba.ttl3.transmitter.ThreadLocalTransmitRegistry}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl3.transmitter.Transmitter\n * @see com.alibaba.ttl3.transmitter.TransmitteeRegistry\n * @see com.alibaba.ttl3.transmitter.Transmittee\n * @see com.alibaba.ttl3.transmitter.ThreadLocalTransmitRegistry\n */\npackage com.alibaba.ttl3.transmitter;\n"
  },
  {
    "path": "ttl-core/src/main/javadoc/overview.html",
    "content": "<html>\n<body>\n<p>This is the API documentation for the\n    <a href=\"https://github.com/alibaba/transmittable-thread-local\" target=\"_top\">📌 TransmittableThreadLocal(TTL)</a>,\n    The missing Java™ std lib(simple &amp; 0-dependency) for framework/middleware,\n    provide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.\n</p>\n</body>\n</html>\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/Utils.kt",
    "content": "package com.alibaba\n\nimport com.alibaba.ttl3.TtlCallable\nimport com.alibaba.ttl3.TtlRunnable\nimport com.alibaba.ttl3.agent.TtlAgentStatus\nimport io.kotest.assertions.withClue\nimport io.kotest.matchers.booleans.shouldBeFalse\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport io.kotest.matchers.shouldBe\nimport java.lang.Thread.sleep\nimport java.time.Duration\nimport java.util.concurrent.*\n\n/**\n * Expand thread pool, to pre-create and cache threads.\n */\nfun expandThreadPool(executor: ExecutorService) {\n    val cpuCountX2 = Runtime.getRuntime().availableProcessors() * 2\n\n    val count = if (executor is ThreadPoolExecutor) {\n        (executor.maximumPoolSize * 2).coerceAtMost(cpuCountX2)\n    } else cpuCountX2\n\n    (0 until count).map {\n        executor.submit { sleep(10) }\n    }.forEach { it.getForTest() }\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n// shutdown/await util methods for test\n////////////////////////////////////////////////////////////////////////////////\n\nprivate val timeout = Duration.ofSeconds(3)\n\nfun ExecutorService.shutdownForTest() {\n    shutdown()\n    withClue(\"Fail to shutdown thread pool\") {\n        awaitTermination(timeout.toMillis(), TimeUnit.MILLISECONDS).shouldBeTrue()\n    }\n}\n\nfun <T> Future<T>.getForTest(): T = this.get(timeout.toMillis(), TimeUnit.MILLISECONDS)\n\n\n////////////////////////////////////////////////////////////////////////////////\n// TTL Agent\n////////////////////////////////////////////////////////////////////////////////\n\nfun hasTtlAgentRun(): Boolean = TtlAgentStatus.getInstance().isTtlAgentLoaded.also {\n    val key = \"run-ttl-test-under-agent\"\n    if (it) {\n        System.getProperties().containsKey(key).shouldBeTrue()\n        System.getProperty(key) shouldBe \"true\"\n    } else {\n        System.getProperties().containsKey(key).shouldBeFalse()\n    }\n}\n\nfun noTtlAgentRun(): Boolean = !hasTtlAgentRun()\n\nfun Runnable.ttlWrapIfNoTtlAgentRun() =\n    if (noTtlAgentRun()) TtlRunnable.get(this)!!\n    else this\n\nfun <T> Callable<T>.ttlWrapIfNoTtlAgentRun() =\n    if (noTtlAgentRun()) TtlCallable.get(this)!!\n    else this\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/cow/CowDemo.kt",
    "content": "package com.alibaba.demo.cow\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport com.alibaba.ttl3.executor.TtlExecutors\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport java.util.concurrent.TimeUnit\n\nfun main() {\n    val threadPool: ExecutorService = Executors.newCachedThreadPool().let {\n        expandThreadPool(it)\n        TtlExecutors.getTtlExecutorService(it)\n    }!!\n\n    traceContext.print()\n    threadPool.execute {\n        traceContext.print()\n        traceContext.increaseSpan()\n        traceContext.print()\n\n        threadPool.execute {\n            traceContext.print()\n            traceContext.increaseSpan()\n            traceContext.print()\n        }\n    }\n\n    Thread.sleep(100)\n    threadPool.shutdown()\n    threadPool.awaitTermination(1, TimeUnit.SECONDS)\n}\n\nprivate val traceContext = object : TransmittableThreadLocal<Trace>() {\n    override fun initialValue(): Trace = Trace(\"init\", Span(\"first\", 0))\n    override fun transmitteeValue(parentValue: Trace): Trace = parentValue.copy() // shadow copy Trace, this is fast\n    override fun childValue(parentValue: Trace): Trace = parentValue.copy() // shadow copy Trace, this is fast\n\n    fun increaseSpan() {\n        get().run {\n            // COW the Span object in Trace\n            span = span.copy(id = \"${span.id} + PONG\", counter = span.counter + 1)\n        }\n    }\n\n    override fun toString(): String {\n        return \"${get()}[${super.toString()}]\"\n    }\n}\n\n\nprivate fun TransmittableThreadLocal<Trace>.print() {\n    println(\"${Thread.currentThread().name}: $this\")\n}\n\nprivate data class Trace(var name: String, var span: Span)\n\nprivate data class Span(val id: String, val counter: Int)\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/forkjoinpool/ForkJoinPoolDemo.kt",
    "content": "package com.alibaba.demo.forkjoinpool\n\nimport java.util.concurrent.ForkJoinPool\nimport java.util.concurrent.RecursiveTask\n\n/**\n * ForkJoinPool use demo.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val pool = ForkJoinPool.commonPool()\n\n    val result = pool.invoke(SumTask(1..1000))\n\n    println(\"computed result: $result\") // result is 500500\n}\n\nprivate class SumTask(private val numbers: IntRange, private val forkLevel: Int = 0) : RecursiveTask<Int>() {\n    override fun compute(): Int =\n        if (numbers.count() <= 16) {\n            println(String.format(\"direct compute %9s[%4s] at fork level %2s @ thread ${Thread.currentThread().name}\",\n                numbers, numbers.count(), forkLevel))\n\n            // compute directly\n            numbers.sum()\n        } else {\n            println(String.format(\"fork   compute %9s[%4s] at fork level %2s @ thread ${Thread.currentThread().name}\",\n                numbers, numbers.count(), forkLevel))\n\n            // split task\n            val middle = numbers.first + numbers.count() / 2\n            val nextForkLevel = forkLevel + 1\n            val taskLeft = SumTask(numbers.first until middle, nextForkLevel)\n            val taskRight = SumTask(middle..numbers.last, nextForkLevel)\n\n            // fork-join compute\n            taskLeft.fork()\n            taskRight.fork()\n            taskLeft.join() + taskRight.join()\n        }\n}\n\n/*\nOutput:\n\nfork   compute   1..1000[1000] at fork level  0 @ thread main\nfork   compute    1..500[ 500] at fork level  1 @ thread ForkJoinPool.commonPool-worker-19\nfork   compute 501..1000[ 500] at fork level  1 @ thread ForkJoinPool.commonPool-worker-5\nfork   compute  501..750[ 250] at fork level  2 @ thread ForkJoinPool.commonPool-worker-23\nfork   compute 751..1000[ 250] at fork level  2 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  251..500[ 250] at fork level  2 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  501..625[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute    1..250[ 250] at fork level  2 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  751..875[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute 876..1000[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  251..375[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  376..500[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  751..812[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute    1..125[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  376..437[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  876..937[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  626..750[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  376..406[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute     1..62[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  751..781[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  501..562[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  251..312[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  626..687[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  751..765[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  876..906[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  563..625[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  501..531[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute     1..31[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  876..890[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  376..390[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  563..593[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute     1..15[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  766..781[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  626..656[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  391..406[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  251..281[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute    16..31[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  563..577[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  891..906[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  407..437[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute    32..62[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  578..593[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  501..515[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  407..421[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  907..937[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  251..265[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  626..640[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  782..812[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  907..921[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  266..281[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  516..531[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  422..437[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  594..625[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  922..937[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute    32..46[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  532..562[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  282..312[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  782..796[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute    47..62[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  641..656[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  797..812[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute   63..125[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  282..296[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  532..546[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute 938..1000[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute    63..93[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  594..609[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  438..500[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  547..562[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  297..312[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  813..875[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  657..687[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  438..468[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  313..375[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  610..625[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute    63..77[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  438..452[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  938..968[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  344..375[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute    78..93[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  688..750[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute   94..125[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  938..952[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  688..718[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute   94..109[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  313..343[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  657..671[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  813..843[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  110..125[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  672..687[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-23\nfork   compute  719..750[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  813..827[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  688..702[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  953..968[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  453..468[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  344..359[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  703..718[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  828..843[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  719..734[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  126..250[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  313..327[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  844..875[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  735..750[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  360..375[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  469..500[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute 969..1000[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  860..875[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  188..250[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  485..500[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-23\ndirect compute  969..984[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  844..859[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  126..187[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  328..343[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  219..250[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-23\nfork   compute  188..218[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  126..156[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute 985..1000[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  469..484[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  188..202[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  219..234[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-23\ndirect compute  203..218[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  157..187[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  126..140[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  141..156[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  235..250[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-5\ndirect compute  172..187[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  157..171[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ncomputed result: 500500\n\n */\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/forkjoinpool/ParallelStreamDemo.kt",
    "content": "package com.alibaba.demo.forkjoinpool\n\nimport java.util.concurrent.ConcurrentSkipListSet\n\n/**\n * Parallel Stream use demo.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    println(\"availableProcessors: ${Runtime.getRuntime().availableProcessors()}\")\n\n    val threadNames: MutableSet<String> = ConcurrentSkipListSet()\n\n    (0..100).toList().stream().parallel().mapToInt {\n        threadNames.add(Thread.currentThread().name)\n        Thread.sleep(10)\n        println(\"map $it @ thread ${Thread.currentThread().name}\")\n\n        it\n    }.sum().let {\n        println(\"sum result: $it\")\n    }\n\n    println(threadNames.joinToString(\n        separator = \"\\n\\t\",\n        prefix = \"run threads(${threadNames.size}):\\n\\t\"\n    ))\n}\n\n/*\nOutput:\n\navailableProcessors: 12\nmap 78 @ thread ForkJoinPool.commonPool-worker-7\nmap 76 @ thread ForkJoinPool.commonPool-worker-21\nmap 91 @ thread ForkJoinPool.commonPool-worker-19\nmap 71 @ thread ForkJoinPool.commonPool-worker-13\nmap 65 @ thread main\nmap 97 @ thread ForkJoinPool.commonPool-worker-3\nmap 32 @ thread ForkJoinPool.commonPool-worker-5\nmap 15 @ thread ForkJoinPool.commonPool-worker-9\nmap 79 @ thread ForkJoinPool.commonPool-worker-17\nmap 82 @ thread ForkJoinPool.commonPool-worker-27\nmap 53 @ thread ForkJoinPool.commonPool-worker-31\nmap 57 @ thread ForkJoinPool.commonPool-worker-23\nmap 77 @ thread ForkJoinPool.commonPool-worker-21\nmap 86 @ thread ForkJoinPool.commonPool-worker-7\nmap 72 @ thread ForkJoinPool.commonPool-worker-13\nmap 92 @ thread ForkJoinPool.commonPool-worker-19\nmap 66 @ thread main\nmap 83 @ thread ForkJoinPool.commonPool-worker-27\nmap 58 @ thread ForkJoinPool.commonPool-worker-23\nmap 54 @ thread ForkJoinPool.commonPool-worker-31\nmap 98 @ thread ForkJoinPool.commonPool-worker-3\nmap 33 @ thread ForkJoinPool.commonPool-worker-5\nmap 16 @ thread ForkJoinPool.commonPool-worker-9\nmap 80 @ thread ForkJoinPool.commonPool-worker-17\nmap 75 @ thread ForkJoinPool.commonPool-worker-21\nmap 87 @ thread ForkJoinPool.commonPool-worker-7\nmap 93 @ thread ForkJoinPool.commonPool-worker-19\nmap 73 @ thread ForkJoinPool.commonPool-worker-13\nmap 67 @ thread main\nmap 81 @ thread ForkJoinPool.commonPool-worker-27\nmap 56 @ thread ForkJoinPool.commonPool-worker-23\nmap 55 @ thread ForkJoinPool.commonPool-worker-31\nmap 17 @ thread ForkJoinPool.commonPool-worker-9\nmap 99 @ thread ForkJoinPool.commonPool-worker-3\nmap 31 @ thread ForkJoinPool.commonPool-worker-5\nmap 84 @ thread ForkJoinPool.commonPool-worker-17\nmap 63 @ thread ForkJoinPool.commonPool-worker-19\nmap 89 @ thread ForkJoinPool.commonPool-worker-7\nmap 74 @ thread ForkJoinPool.commonPool-worker-13\nmap 95 @ thread ForkJoinPool.commonPool-worker-21\nmap 62 @ thread ForkJoinPool.commonPool-worker-27\nmap 60 @ thread ForkJoinPool.commonPool-worker-23\nmap 100 @ thread ForkJoinPool.commonPool-worker-3\nmap 51 @ thread ForkJoinPool.commonPool-worker-31\nmap 13 @ thread ForkJoinPool.commonPool-worker-9\nmap 35 @ thread ForkJoinPool.commonPool-worker-5\nmap 85 @ thread ForkJoinPool.commonPool-worker-17\nmap 64 @ thread ForkJoinPool.commonPool-worker-19\nmap 90 @ thread ForkJoinPool.commonPool-worker-7\nmap 69 @ thread ForkJoinPool.commonPool-worker-13\nmap 96 @ thread ForkJoinPool.commonPool-worker-21\nmap 94 @ thread ForkJoinPool.commonPool-worker-27\nmap 61 @ thread ForkJoinPool.commonPool-worker-23\nmap 14 @ thread ForkJoinPool.commonPool-worker-9\nmap 36 @ thread ForkJoinPool.commonPool-worker-5\nmap 44 @ thread ForkJoinPool.commonPool-worker-3\nmap 52 @ thread ForkJoinPool.commonPool-worker-31\nmap 88 @ thread ForkJoinPool.commonPool-worker-17\nmap 68 @ thread ForkJoinPool.commonPool-worker-19\nmap 40 @ thread ForkJoinPool.commonPool-worker-7\nmap 70 @ thread ForkJoinPool.commonPool-worker-13\nmap 48 @ thread ForkJoinPool.commonPool-worker-21\nmap 46 @ thread ForkJoinPool.commonPool-worker-27\nmap 59 @ thread ForkJoinPool.commonPool-worker-23\nmap 12 @ thread ForkJoinPool.commonPool-worker-9\nmap 34 @ thread ForkJoinPool.commonPool-worker-5\nmap 50 @ thread ForkJoinPool.commonPool-worker-31\nmap 38 @ thread ForkJoinPool.commonPool-worker-17\nmap 45 @ thread ForkJoinPool.commonPool-worker-3\nmap 41 @ thread ForkJoinPool.commonPool-worker-7\nmap 43 @ thread ForkJoinPool.commonPool-worker-19\nmap 28 @ thread ForkJoinPool.commonPool-worker-13\nmap 49 @ thread ForkJoinPool.commonPool-worker-21\nmap 47 @ thread ForkJoinPool.commonPool-worker-27\nmap 7 @ thread ForkJoinPool.commonPool-worker-23\nmap 21 @ thread ForkJoinPool.commonPool-worker-9\nmap 25 @ thread ForkJoinPool.commonPool-worker-3\nmap 3 @ thread ForkJoinPool.commonPool-worker-31\nmap 26 @ thread ForkJoinPool.commonPool-worker-5\nmap 39 @ thread ForkJoinPool.commonPool-worker-17\nmap 42 @ thread ForkJoinPool.commonPool-worker-7\nmap 19 @ thread ForkJoinPool.commonPool-worker-19\nmap 29 @ thread ForkJoinPool.commonPool-worker-13\nmap 1 @ thread ForkJoinPool.commonPool-worker-21\nmap 0 @ thread ForkJoinPool.commonPool-worker-27\nmap 8 @ thread ForkJoinPool.commonPool-worker-23\nmap 27 @ thread ForkJoinPool.commonPool-worker-5\nmap 22 @ thread ForkJoinPool.commonPool-worker-9\nmap 37 @ thread ForkJoinPool.commonPool-worker-17\nmap 4 @ thread ForkJoinPool.commonPool-worker-3\nmap 10 @ thread ForkJoinPool.commonPool-worker-31\nmap 20 @ thread ForkJoinPool.commonPool-worker-19\nmap 18 @ thread ForkJoinPool.commonPool-worker-7\nmap 30 @ thread ForkJoinPool.commonPool-worker-13\nmap 2 @ thread ForkJoinPool.commonPool-worker-21\nmap 23 @ thread ForkJoinPool.commonPool-worker-23\nmap 6 @ thread ForkJoinPool.commonPool-worker-27\nmap 9 @ thread ForkJoinPool.commonPool-worker-5\nmap 5 @ thread ForkJoinPool.commonPool-worker-3\nmap 11 @ thread ForkJoinPool.commonPool-worker-31\nmap 24 @ thread ForkJoinPool.commonPool-worker-23\nsum result: 5050\nrun threads(12):\n\tForkJoinPool.commonPool-worker-13\n\tForkJoinPool.commonPool-worker-17\n\tForkJoinPool.commonPool-worker-19\n\tForkJoinPool.commonPool-worker-21\n\tForkJoinPool.commonPool-worker-23\n\tForkJoinPool.commonPool-worker-27\n\tForkJoinPool.commonPool-worker-3\n\tForkJoinPool.commonPool-worker-31\n\tForkJoinPool.commonPool-worker-5\n\tForkJoinPool.commonPool-worker-7\n\tForkJoinPool.commonPool-worker-9\n\tmain\n\n */\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/scheduled_thread_pool_executor/ScheduledFutureTaskDemo.kt",
    "content": "package com.alibaba.demo.scheduled_thread_pool_executor\n\nimport java.util.concurrent.ScheduledThreadPoolExecutor\nimport java.util.concurrent.TimeUnit\n\n/**\n * ScheduledThreadPoolExecutor usage demo for Issue 148\n * https://github.com/alibaba/transmittable-thread-local/issues/148\n */\nfun main() {\n    val scheduledThreadPoolExecutor = ScheduledThreadPoolExecutor(10)\n\n    val task = Runnable { println(\"I'm a Runnable task, I'm working...\") }\n    val scheduledFuture = scheduledThreadPoolExecutor.scheduleWithFixedDelay(task, 500, 500, TimeUnit.MILLISECONDS)\n\n    Thread.sleep(2_000)\n\n    println(\"cancel\")\n    val cancelResult = scheduledFuture.cancel(false)\n    println(\"canceled: $cancelResult\")  // scheduled task cancel success!\n\n    Thread.sleep(2_000)\n    scheduledThreadPoolExecutor.shutdown()\n    println(\"Bye\")\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/session_cache/SessionCacheDemo.kt",
    "content": "package com.alibaba.demo.session_cache\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport com.alibaba.ttl3.TtlRunnable\nimport com.alibaba.ttl3.executor.TtlExecutors\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport io.reactivex.Flowable\nimport io.reactivex.plugins.RxJavaPlugins\nimport io.reactivex.schedulers.Schedulers\nimport java.util.concurrent.*\n\n\nclass SessionCacheDemo : AnnotationSpec() {\n    @Test\n    fun invokeInThreadOfThreadPool() {\n        val bizService = BizService()\n        val printer: () -> Unit =\n            { System.out.printf(\"[%20s] cache: %s%n\", Thread.currentThread().name, bizService.getCacheItem()) }\n\n        executorService.submit(Callable {\n            bizService.getItemByCache().also { printer() }\n        }).get()\n\n        printer()\n\n        // here service invocation will use item cache\n        bizService.getItemByCache()\n        printer()\n    }\n\n    @Test\n    fun invokeInThreadOfRxJava() {\n        val bizService = BizService()\n        val printer: (Item) -> Unit =\n            { System.out.printf(\"[%30s] cache: %s%n\", Thread.currentThread().name, bizService.getCacheItem()) }\n\n        Flowable.just(bizService)\n            .observeOn(Schedulers.io())\n            .map(BizService::getItemByCache)\n            .doOnNext(printer)\n            .blockingSubscribe(printer)\n\n        // here service invocation will use item cache\n        bizService.getItemByCache()\n            .let(printer)\n    }\n\n    @BeforeAll\n    fun beforeAll() {\n        // expand Schedulers.io()\n        (0 until Runtime.getRuntime().availableProcessors() * 2)\n            .map {\n                FutureTask {\n                    Thread.sleep(10)\n                    it\n                }.apply { Schedulers.io().scheduleDirect(this) }\n            }\n            .forEach { it.get() }\n\n        // TTL integration for RxJava\n        RxJavaPlugins.setScheduleHandler(TtlRunnable::get)\n    }\n\n\n    @AfterAll\n    fun afterAll() {\n        executorService.shutdown()\n        // Fail to shut down thread pool\n        executorService.awaitTermination(1, TimeUnit.SECONDS).shouldBeTrue()\n    }\n\n    @After\n    fun tearDown() {\n        BizService.clearCache()\n    }\n\n    companion object {\n        private val executorService = Executors.newFixedThreadPool(3).let {\n            expandThreadPool(it)\n            // TTL integration for thread pool\n            TtlExecutors.getTtlExecutorService(it)!!\n        }\n    }\n}\n\n/**\n * Mock Service\n */\nprivate class BizService {\n    init {\n        // NOTE: AVOID cache object lazy init\n        getCache()\n    }\n\n    fun getItem(): Item = Item(ThreadLocalRandom.current().nextInt(0, 10_000))\n\n    /**\n     * get biz data, usually use spring cache. here is simple implementation\n     */\n    fun getItemByCache(): Item {\n        return getCache().computeIfAbsent(ONLY_KEY) { getItem() }\n    }\n\n    fun getCacheItem(): Item? = getCache()[ONLY_KEY]\n\n    companion object {\n        private const val ONLY_KEY = \"ONLY_KEY\"\n\n        private val cacheContext = object : TransmittableThreadLocal<ConcurrentMap<String, Item>>() {\n            // init cache\n            override fun initialValue(): ConcurrentMap<String, Item> = ConcurrentHashMap()\n        }\n\n        private fun getCache() = cacheContext.get()\n\n        fun clearCache() {\n            getCache().clear()\n        }\n    }\n}\n\n/**\n * Mock Cache Data\n */\nprivate data class Item(val id: Int)\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/timer/TimerTaskDemo.kt",
    "content": "package com.alibaba.demo.timer\n\nimport java.text.SimpleDateFormat\nimport java.util.*\n\n/**\n * @see [Java Timer TimerTask Example](https://www.journaldev.com/1050/java-timer-timertask-example)\n */\nfun main() {\n    val timerTask = MyTimerTask()\n\n    // running timer task as daemon thread\n    val timer = Timer(true)\n    timer.scheduleAtFixedRate(timerTask, 0, 300)\n    println(\"TimerTask scheduled\")\n\n    // cancel after sometime\n    Thread.sleep(1_000)\n    timer.cancel()\n    println(\"TimerTask cancelled\")\n\n    Thread.sleep(300)\n}\n\nprivate class MyTimerTask : TimerTask() {\n    override fun run() {\n        val format = SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\")\n        println(\"Timer task started at: ${format.format(Date())}\")\n        Thread.sleep(200)\n        println(\"Timer task finished at: ${format.format(Date())}\")\n    }\n\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/ttl3/CustomizedBlockingQueueWithTtlDemo.java",
    "content": "package com.alibaba.demo.ttl3;\n\nimport com.alibaba.ttl3.TtlRunnable;\nimport com.alibaba.ttl3.executor.TtlExecutors;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Simple demo code for issue\n * https://github.com/alibaba/transmittable-thread-local/issues/340\n */\npublic class CustomizedBlockingQueueWithTtlDemo {\n    public static void main(String[] args) throws Exception {\n        final MyBlockingQueue myBlockingQueue = new MyBlockingQueue();\n\n        final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(\n                1, 1, 1L, TimeUnit.SECONDS, myBlockingQueue);\n        final ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(threadPoolExecutor);\n\n        ttlExecutorService.execute(new MyTask(\"accept-1\"));\n        ttlExecutorService.execute(new MyTask(\"DISCARDED\"));\n        ttlExecutorService.execute(new MyTask(\"accept-2\"));\n\n        ttlExecutorService.shutdown();\n        if (!ttlExecutorService.awaitTermination(10, TimeUnit.SECONDS)) {\n            throw new IllegalStateException(\"Fail to shutdown executor service\");\n        }\n    }\n\n    private static class MyTask implements Runnable {\n        private final String msg;\n\n        private MyTask(String msg) {\n            this.msg = msg;\n        }\n\n        @Override\n        public void run() {\n            System.out.println(\"MyTask: \" + msg);\n        }\n    }\n\n    private static class MyBlockingQueue extends ArrayBlockingQueue<Runnable> {\n        public MyBlockingQueue() {\n            super(16);\n        }\n\n        @Override\n        public boolean offer(@NonNull Runnable runnable) {\n            // unwrap TtlRunnable first\n            final Runnable unwrap  = TtlRunnable.unwrap(runnable);\n\n            final MyTask myTask = (MyTask) unwrap;\n            if (myTask.msg.startsWith(\"accept-\")) {\n                // ignore result/return value of offer, BAD!!\n                //   does not follow the contract of method offer\n                // this is just a simple demo!\n                super.offer(runnable);\n            }\n\n            // always return true even if discard the task, BAD!!\n            //   does not follow the contract of method offer\n            // this is just a simple demo!\n            return true;\n        }\n\n        @Override\n        public void put(@NonNull Runnable runnable) throws InterruptedException {\n            // unwrap TtlRunnable first\n            final Runnable unwrap  = TtlRunnable.unwrap(runnable);\n\n            final MyTask myTask = (MyTask) unwrap;\n            // discard task if not satisfied, BAD!!\n            //   does not follow the contract of method put\n            // this is just a simple demo!\n            if (myTask.msg.startsWith(\"accept-\")) {\n                super.put(runnable);\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/ttl3/SimpleDemo.kt",
    "content": "package com.alibaba.demo.ttl3\n\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport kotlin.concurrent.thread\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val context = TransmittableThreadLocal<String>()\n\n    context.set(\"value-set-in-parent\")\n    println(\"[parent thread] set ${context.get()}\")\n\n    /////////////////////////////////////\n    // create sub-thread\n    /////////////////////////////////////\n    thread {\n        val value = context.get()\n        println(\"[child thread] get $value\")\n    }.join()\n\n    println(\"[parent thread] get ${context.get()}\")\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/ttl3/TtlExecutorServiceWithPriorityBlockingQueueDemo.kt",
    "content": "package com.alibaba.demo.ttl3\n\nimport com.alibaba.ttl3.executor.TtlExecutors\nimport java.lang.Thread.sleep\nimport java.util.concurrent.BlockingQueue\nimport java.util.concurrent.PriorityBlockingQueue\nimport java.util.concurrent.ThreadPoolExecutor\nimport java.util.concurrent.TimeUnit\n\nfun main() {\n    demoSubmitComparableTaskToTtlExecutorServiceWithPriorityBlockingQueue()\n\n    demoSubmitOrderTaskToTtlExecutorServiceWithPriorityBlockingQueue()\n}\n\n/**\n * Demo for cooperation TTL executor(ThreadPoolExecutor) with PriorityBlockingQueue, for Comparable Runnable.\n *\n * if you use TTL Agent, no extra work(getTtlRunnableUnwrapComparatorForComparableRunnable) is need.\n * aka. rewriting PriorityBlockingQueue by TTL Agent automatically and transparently.\n */\nprivate fun demoSubmitComparableTaskToTtlExecutorServiceWithPriorityBlockingQueue() {\n    val comparator: Comparator<Runnable> = TtlExecutors.getTtlRunnableUnwrapComparatorForComparableRunnable()\n\n    // explicit PriorityBlockingQueue Comparator argument\n    //   instead of default constructor PriorityBlockingQueue()\n    //\n    // aka. rewrite\n    //     val priorityBlockingQueue                   = PriorityBlockingQueue()\n    // to\n    val priorityBlockingQueue: BlockingQueue<Runnable> = PriorityBlockingQueue(11, comparator)\n\n    val threadPoolExecutor = ThreadPoolExecutor(1, 2, 1, TimeUnit.SECONDS, priorityBlockingQueue)\n    val ttlExecutorService = TtlExecutors.getTtlExecutorService(threadPoolExecutor)!!\n\n    ttlExecutorService.execute(BizComparableTask(0))\n    ttlExecutorService.execute(BizComparableTask(1))\n    ttlExecutorService.execute(BizComparableTask(2))\n    ttlExecutorService.execute(BizComparableTask(42))\n    ttlExecutorService.execute(BizComparableTask(9))\n    ttlExecutorService.execute(BizComparableTask(8))\n    ttlExecutorService.execute(BizComparableTask(7))\n\n    threadPoolExecutor.shutdown()\n    threadPoolExecutor.awaitTermination(5, TimeUnit.SECONDS)\n}\n\n\n/**\n * Demo for cooperation TTL executor(ThreadPoolExecutor) with PriorityBlockingQueue, for Runnable Comparator.\n *\n * if you use TTL Agent, no extra work(getTtlRunnableUnwrapComparator) is need.\n * aka. rewriting Comparator by TTL Agent automatically and transparently.\n */\nprivate fun demoSubmitOrderTaskToTtlExecutorServiceWithPriorityBlockingQueue() {\n    val comparator: Comparator<Runnable> = compareBy { (it as BizOrderTask).order }\n    val ttlRunnableUnwrapComparator: Comparator<Runnable>? = TtlExecutors.getTtlRunnableUnwrapComparator(comparator)\n\n    // use TtlRunnableUnwrapComparator instead original comparator\n    //\n    // aka. rewrite\n    //     val priorityBlockingQueue                           = PriorityBlockingQueue(11, comparator)\n    // to\n    val priorityBlockingQueue: PriorityBlockingQueue<Runnable> = PriorityBlockingQueue(11, ttlRunnableUnwrapComparator)\n\n    val threadPoolExecutor = ThreadPoolExecutor(1, 2, 1, TimeUnit.SECONDS, priorityBlockingQueue)\n    val ttlExecutorService = TtlExecutors.getTtlExecutorService(threadPoolExecutor)!!\n\n    ttlExecutorService.execute(BizOrderTask(0))\n    ttlExecutorService.execute(BizOrderTask(1))\n    ttlExecutorService.execute(BizOrderTask(2))\n    ttlExecutorService.execute(BizOrderTask(42))\n    ttlExecutorService.execute(BizOrderTask(9))\n    ttlExecutorService.execute(BizOrderTask(8))\n    ttlExecutorService.execute(BizOrderTask(7))\n\n    threadPoolExecutor.shutdown()\n    threadPoolExecutor.awaitTermination(5, TimeUnit.SECONDS)\n}\n\n\nprivate data class BizComparableTask(val num: Int) : Runnable, Comparable<Runnable> {\n    override fun run() {\n        sleep(10)\n        println(\"run BizComparableTask $num\")\n    }\n\n    override fun compareTo(other: Runnable): Int = num - (other as BizComparableTask).num\n}\n\nprivate data class BizOrderTask(val order: Int) : Runnable {\n    override fun run() {\n        sleep(10)\n        println(\"run BizOrderTask $order\")\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/ttl3/TtlExecutorWrapperDemo.kt",
    "content": "package com.alibaba.demo.ttl3\n\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport com.alibaba.ttl3.executor.TtlExecutors\nimport java.util.concurrent.Callable\nimport java.util.concurrent.Executors\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val ttlExecutorService = Executors.newCachedThreadPool().let {\n        // return TTL wrapper from normal ExecutorService\n        TtlExecutors.getTtlExecutorService(it)\n    }!!\n    val context = TransmittableThreadLocal<String>()\n\n    context.set(\"value-set-in-parent\")\n    println(\"[parent thread] set ${context.get()}\")\n\n    /////////////////////////////////////\n    // Runnable\n    /////////////////////////////////////\n    val task = Runnable { println(\"[child thread] get ${context.get()} in Runnable\") }\n    ttlExecutorService.submit(task).get()\n\n    /////////////////////////////////////\n    // Callable\n    /////////////////////////////////////\n    val call = Callable {\n        println(\"[child thread] get ${context.get()} in Callable\")\n        42\n    }\n    ttlExecutorService.submit(call).get()\n\n    /////////////////////////////////////\n    // cleanup\n    /////////////////////////////////////\n    ttlExecutorService.shutdown()\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/ttl3/TtlForkJoinTaskDemo.kt",
    "content": "package com.alibaba.demo.ttl3\n\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport com.alibaba.ttl3.TtlRecursiveTask\nimport java.util.concurrent.ForkJoinPool\n\n\nval context = TransmittableThreadLocal<String>().apply {\n    set(\"value-set-in-parent\")\n    println(\"[parent thread] set ${get()} @ thread ${Thread.currentThread().name}\")\n}\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val pool = ForkJoinPool.commonPool()\n\n    val result = pool.invoke(SumTask(1..1000))\n\n    println(\"[parent thread] computed result: $result @ thread ${Thread.currentThread().name}\") // result is 500500\n}\n\nprivate class SumTask(private val numbers: IntRange, private val forkLevel: Int = 0) : TtlRecursiveTask<Int>() {\n    override fun compute(): Int =\n        if (numbers.count() <= 16) {\n            println(String.format(\"direct compute %9s[%4s] with context ${context.get()} at fork level %2s @ thread ${Thread.currentThread().name}\",\n                numbers, numbers.count(), forkLevel))\n\n            // compute directly\n            numbers.sum()\n        } else {\n            println(String.format(\"fork   compute %9s[%4s] with context ${context.get()} at fork level %2s @ thread ${Thread.currentThread().name}\",\n                numbers, numbers.count(), forkLevel))\n\n            // split task\n            val middle = numbers.first + numbers.count() / 2\n            val nextForkLevel = forkLevel + 1\n            val taskLeft = SumTask(numbers.first until middle, nextForkLevel)\n            val taskRight = SumTask(middle..numbers.last, nextForkLevel)\n\n            // fork-join compute\n            taskLeft.fork()\n            taskRight.fork()\n            taskLeft.join() + taskRight.join()\n        }\n}\n\n/*\nOutput:\n\n[parent thread] set value-set-in-parent @ thread main\nfork   compute   1..1000[1000] with context value-set-in-parent at fork level  0 @ thread main\nfork   compute 501..1000[ 500] with context value-set-in-parent at fork level  1 @ thread ForkJoinPool.commonPool-worker-5\nfork   compute    1..500[ 500] with context value-set-in-parent at fork level  1 @ thread ForkJoinPool.commonPool-worker-19\nfork   compute    1..250[ 250] with context value-set-in-parent at fork level  2 @ thread ForkJoinPool.commonPool-worker-23\nfork   compute  251..500[ 250] with context value-set-in-parent at fork level  2 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute 751..1000[ 250] with context value-set-in-parent at fork level  2 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  501..750[ 250] with context value-set-in-parent at fork level  2 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  126..250[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  251..375[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute 876..1000[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute    1..125[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  751..875[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  376..500[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  126..187[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  251..312[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute     1..62[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  501..625[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  751..812[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  876..937[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  376..437[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  126..156[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute     1..31[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  251..281[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  751..781[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  501..562[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  376..406[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute     1..15[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  876..906[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  251..265[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  126..140[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  751..765[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  501..531[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  376..390[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  266..281[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  141..156[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute    16..31[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  876..890[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  501..515[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  766..781[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  282..312[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  391..406[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  891..906[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute    32..62[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  157..187[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  782..812[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  516..531[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  282..296[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute    32..46[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  407..437[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  532..562[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  157..171[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  907..937[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute    47..62[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  532..546[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  297..312[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  782..796[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  907..921[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  172..187[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  407..421[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  313..375[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  797..812[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  547..562[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute   63..125[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  422..437[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  188..250[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  922..937[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  563..625[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  813..875[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  313..343[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  438..500[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute    63..93[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  563..593[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  313..327[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute    63..77[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute 938..1000[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  188..218[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  328..343[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute    78..93[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  563..577[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  438..468[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  813..843[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute   94..125[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  344..375[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  188..202[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  438..452[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  938..968[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute   94..109[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  813..827[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  578..593[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  110..125[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  938..952[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  453..468[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  203..218[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  344..359[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  594..625[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  828..843[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  469..500[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  219..250[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  953..968[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  844..875[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  594..609[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  360..375[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  219..234[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  469..484[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  610..625[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  844..859[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute 969..1000[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  485..500[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  235..250[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  626..750[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  860..875[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  969..984[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute 985..1000[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  688..750[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  626..687[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  688..718[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  719..750[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  657..687[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  626..656[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  688..702[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  719..734[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-19\ndirect compute  703..718[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  626..640[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  672..687[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  657..671[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  735..750[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-23\ndirect compute  641..656[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-19\n[parent thread] computed result: 500500 @ thread main\n\n */\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/demo/ttl3/TtlWrapperDemo.kt",
    "content": "package com.alibaba.demo.ttl3\n\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport com.alibaba.ttl3.TtlCallable\nimport com.alibaba.ttl3.TtlRunnable\nimport java.util.concurrent.Callable\nimport java.util.concurrent.Executors\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val executorService = Executors.newCachedThreadPool()\n    val context = TransmittableThreadLocal<String>()\n\n    context.set(\"value-set-in-parent\")\n    println(\"[parent thread] set ${context.get()}\")\n\n    /////////////////////////////////////\n    // Runnable / TtlRunnable\n    /////////////////////////////////////\n    val task = Runnable { println(\"[child thread] get ${context.get()} in Runnable\") }\n    val ttlRunnable = TtlRunnable.get(task)!!\n\n    executorService.submit(ttlRunnable).get()\n\n    /////////////////////////////////////\n    // Callable / TtlCallable\n    /////////////////////////////////////\n    val call = Callable {\n        println(\"[child thread] get ${context.get()} in Callable\")\n        42\n    }\n    val ttlCallable = TtlCallable.get(call)!!\n\n    executorService.submit(ttlCallable).get()\n\n    /////////////////////////////////////\n    // cleanup\n    /////////////////////////////////////\n    executorService.shutdown()\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/perf/Utils.kt",
    "content": "package com.alibaba.perf\n\nimport java.util.*\n\nprivate val random = Random()\n\ninternal fun bytes2Hex(bytes: ByteArray): String {\n    val sb = StringBuilder(1024)\n    for (b in bytes) {\n        val s = Integer.toHexString(b.toInt() and 0xFF)\n        sb.append(if (s.length == 1) \"0$s\" else s)\n    }\n    return sb.toString()\n}\n\ninternal fun getRandomBytes(): ByteArray {\n    val bytes = ByteArray(1024)\n    random.nextBytes(bytes)\n    return bytes\n}\n\ninternal fun getRandomString(): String {\n    return bytes2Hex(getRandomBytes())\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/perf/memoryleak/NoMemoryLeak_ThreadLocal_NoRemove.kt",
    "content": "package com.alibaba.perf.memoryleak\n\nimport com.alibaba.perf.getRandomString\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    var counter: Long = 0\n    while (true) {\n        val threadLocal = ThreadLocal<String>()\n        threadLocal.set(getRandomString())\n\n        if (counter % 1000 == 0L)\n            System.out.printf(\"%05dK%n\", counter / 1000)\n        counter++\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/perf/memoryleak/NoMemoryLeak_TransmittableThreadLocal_NoRemove.kt",
    "content": "package com.alibaba.perf.memoryleak\n\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport com.alibaba.perf.getRandomString\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    var counter: Long = 0\n    while (true) {\n        val threadLocal = TransmittableThreadLocal<String>()\n        threadLocal.set(getRandomString())\n\n        if (counter % 1000 == 0L)\n            System.out.printf(\"%05dK%n\", counter / 1000)\n        counter++\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/perf/package-info.java",
    "content": "/**\n * Performance test cases.\n * <p>\n * TPS test:\n * <ul>\n *     <li>{@link com.alibaba.perf.tps.CreateTransmittableThreadLocalInstanceTpsKt#main()}</li>\n *     <li>{@link com.alibaba.perf.tps.CreateThreadLocalInstanceTpsKt#main()}</li>\n * </ul>\n * <p>\n * Memory leak test:\n * <ul>\n *    <li>{@link com.alibaba.perf.memoryleak.NoMemoryLeak_TransmittableThreadLocal_NoRemoveKt#main()}</li>\n *    <li>{@link com.alibaba.perf.memoryleak.NoMemoryLeak_ThreadLocal_NoRemoveKt#main()}</li>\n * </ul>\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\npackage com.alibaba.perf;\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/perf/tps/CreateThreadLocalInstanceTps.kt",
    "content": "package com.alibaba.perf.tps\n\nimport com.alibaba.perf.getRandomString\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val tpsCounter = TpsCounter(2)\n\n    tpsCounter.setAction {\n        val threadLocal = ThreadLocal<String>()\n        threadLocal.set(getRandomString())\n    }\n\n    while (true) {\n        val start = tpsCounter.count\n        Thread.sleep(1000)\n        System.out.printf(\"tps: %,d\\n\", tpsCounter.count - start)\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/perf/tps/CreateTransmittableThreadLocalInstanceTps.kt",
    "content": "package com.alibaba.perf.tps\n\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport com.alibaba.perf.getRandomString\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val tpsCounter = TpsCounter(2)\n\n    tpsCounter.setAction {\n        val threadLocal = TransmittableThreadLocal<String>()\n        threadLocal.set(getRandomString())\n    }\n\n    while (true) {\n        val start = tpsCounter.count\n        Thread.sleep(1000)\n        System.out.printf(\"tps: %d\\n\", tpsCounter.count - start)\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/perf/tps/TpsCounter.kt",
    "content": "package com.alibaba.perf.tps\n\nimport com.alibaba.shutdownForTest\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport java.util.concurrent.atomic.AtomicLong\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass TpsCounter internal constructor(private val threadCount: Int) {\n    private val executorService: ExecutorService = Executors.newFixedThreadPool(threadCount)\n\n    private val counter = AtomicLong()\n\n    @Volatile\n    private var stopped = false\n\n    val count: Long\n        get() = counter.get()\n\n    internal fun setAction(runnable: Runnable) {\n        val r = {\n            while (!stopped) {\n                runnable.run()\n                counter.incrementAndGet()\n            }\n        }\n        for (i in 0 until threadCount) {\n            executorService.execute(r)\n        }\n    }\n\n    fun stop() {\n        stopped = true\n        executorService.shutdownForTest()\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/third_part_lib_test/ExecutorsTest.kt",
    "content": "package com.alibaba.third_part_lib_test\n\nimport com.alibaba.shutdownForTest\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.booleans.shouldBeFalse\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport java.util.concurrent.Executors\nimport java.util.concurrent.ThreadPoolExecutor\n\n\nclass ExecutorsTest : AnnotationSpec() {\n    @Test\n    fun test_remove_of_ThreadPoolExecutor() {\n        val size = 2\n        val threadPool = Executors.newFixedThreadPool(size) as ThreadPoolExecutor\n\n        val futures = (0..size * 2).map {\n            threadPool.submit {\n                Thread.sleep(10)\n            }\n        }\n\n        Runnable {\n            println(\"Task should be removed!\")\n        }.let {\n            threadPool.execute(it)\n\n            threadPool.remove(it).shouldBeTrue()\n            threadPool.remove(it).shouldBeFalse()\n        }\n\n        // wait sleep task finished.\n        futures.forEach { it.get() }\n\n        threadPool.shutdownForTest()\n    }\n}\n\n\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/third_part_lib_test/ForkJoinPoolTest.kt",
    "content": "package com.alibaba.third_part_lib_test\n\nimport com.alibaba.shutdownForTest\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.shouldBe\nimport java.util.concurrent.ForkJoinPool\nimport java.util.concurrent.RecursiveTask\nimport java.util.concurrent.atomic.AtomicInteger\n\nclass ForkJoinPoolTest : AnnotationSpec() {\n    @Test\n    fun test_sameTaskDirectReturn_onlyExec1Time_ifHaveRun() {\n        val pool = ForkJoinPool()\n\n        val numbers = 1L..100L\n        val sumTask = SumTask(numbers)\n\n        // same task instance run 10 times\n        for (i in 0..9) {\n            pool.invoke(sumTask) shouldBe numbers.sum()\n        }\n\n        sumTask.execCounter.get() shouldBe 1\n\n        pool.shutdownForTest()\n    }\n}\n\nprivate class SumTask(private val numbers: LongRange) : RecursiveTask<Long>() {\n    val execCounter = AtomicInteger(0)\n\n    override fun compute(): Long {\n        execCounter.incrementAndGet()\n\n        return if (numbers.count() <= 16) {\n            // compute directly\n            numbers.sum()\n        } else {\n            // split task\n            val middle = numbers.first + numbers.count() / 2\n\n            val taskLeft = SumTask(numbers.first until middle)\n            val taskRight = SumTask(middle..numbers.last)\n\n            taskLeft.fork()\n            taskRight.fork()\n            taskLeft.join() + taskRight.join()\n        }\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/ttl3/TtlCallableTest.kt",
    "content": "package com.alibaba.ttl3\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.getForTest\nimport com.alibaba.shutdownForTest\nimport com.alibaba.ttlWrapIfNoTtlAgentRun\nimport io.kotest.assertions.throwables.shouldThrow\nimport io.kotest.core.spec.style.FunSpec\nimport io.kotest.matchers.collections.shouldBeEmpty\nimport io.kotest.matchers.collections.shouldContainInOrder\nimport io.kotest.matchers.collections.shouldHaveSize\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport io.kotest.matchers.string.shouldContain\nimport io.kotest.matchers.types.shouldBeSameInstanceAs\nimport io.kotest.matchers.types.shouldBeTypeOf\nimport java.util.concurrent.*\nimport kotlin.concurrent.thread\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass TtlCallableTest : FunSpec({\n    lateinit var executorService: ExecutorService\n\n    beforeSpec {\n        executorService = Executors.newFixedThreadPool(3).also { expandThreadPool(it) }\n    }\n\n    afterSpec {\n        executorService.shutdownForTest()\n    }\n\n\n    ttlFlowTest(\"run in current thread\") { checkLogicInTask ->\n        val ttlCallable = TtlCallable.get {\n            checkLogicInTask()\n            42\n        }!!\n\n        val taskRunner: TaskRunner = {\n            // run in the *current* thread\n            ttlCallable.call()\n\n            CompletableFuture.completedFuture(null)\n        }\n        taskRunner\n    }\n\n    ttlFlowTest(\"async run by new thread\") { checkLogicInTask ->\n        val ttlCallable = TtlCallable.get {\n            checkLogicInTask()\n            42\n        }!!\n\n        val taskRunner: TaskRunner = {\n            val future = CompletableFuture<Void>()\n            // run in new thread\n            thread {\n                ttlCallable.call()\n                future.complete(null)\n            }\n            future\n        }\n        taskRunner\n    }\n\n    ttlFlowTest(\"async run by executor service\", captureTimeByAgentRun) { checkLogicInTask ->\n        val callable = Callable {\n            checkLogicInTask()\n            42\n        }.ttlWrapIfNoTtlAgentRun()\n\n        val taskRunner: TaskRunner = {\n            executorService.submit(callable)\n        }\n        taskRunner\n    }\n\n\n    test(\"release ttl value reference after call\") {\n        val call = Callable { 42 }\n        val ttlCallable = TtlCallable.get(call, true)!!\n        ttlCallable.callable shouldBeSameInstanceAs call\n\n        executorService.submit(ttlCallable).getForTest() shouldBe 42\n\n        val exception = shouldThrow<ExecutionException> {\n            executorService.submit(ttlCallable).getForTest()\n        }\n        exception.cause.shouldBeTypeOf<IllegalStateException>()\n        exception.message shouldContain \"TTL value reference is released after call!\"\n    }\n\n    test(\"get same\") {\n        val call = Callable { 42 }\n        val ttlCallable = TtlCallable.get(call)!!\n        ttlCallable.callable shouldBeSameInstanceAs call\n    }\n\n    test(\"get idempotent\") {\n        val call = TtlCallable.get { 42 }\n\n        shouldThrow<IllegalStateException> {\n            TtlCallable.get(call)\n        }.message shouldContain \"Already TtlCallable\"\n    }\n\n    test(\"get null input\") {\n        TtlCallable.get<Any>(null).shouldBeNull()\n    }\n\n    test(\"gets\") {\n        val call1 = Callable { 1 }\n        val call2 = Callable { 2 }\n        val call3 = Callable { 3 }\n\n        val callList = TtlCallable.gets(\n            listOf(call1, call2, null, call3)\n        )\n\n        callList.shouldHaveSize(4)\n        callList[0].shouldBeTypeOf<TtlCallable<*>>()\n        callList[1].shouldBeTypeOf<TtlCallable<*>>()\n        callList[2].shouldBeNull()\n        callList[3].shouldBeTypeOf<TtlCallable<*>>()\n    }\n\n    test(\"unwrap\") {\n        TtlCallable.unwrap<String>(null).shouldBeNull()\n\n        val callable = Callable { \"hello\" }\n        val ttlCallable = TtlCallable.get(callable)\n\n\n        TtlCallable.unwrap(callable) shouldBe callable\n        TtlCallable.unwrap(ttlCallable) shouldBe callable\n\n        TtlWrappers.unwrap(callable) shouldBe callable\n        TtlWrappers.unwrap(ttlCallable) shouldBe callable\n\n\n        TtlCallable.unwraps(listOf(callable)).shouldContainInOrder(callable)\n        TtlCallable.unwraps(listOf(ttlCallable)).shouldContainInOrder(callable)\n\n        TtlCallable.unwraps(listOf(ttlCallable, callable)).shouldContainInOrder(callable, callable)\n        TtlCallable.unwraps<String>(null).shouldBeEmpty()\n    }\n})\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/ttl3/TtlFlowTester.kt",
    "content": "package com.alibaba.ttl3\n\nimport com.alibaba.getForTest\nimport com.alibaba.noTtlAgentRun\nimport io.kotest.assertions.fail\nimport io.kotest.core.spec.style.scopes.FunSpecRootScope\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport java.util.concurrent.CopyOnWriteArraySet\nimport java.util.concurrent.Future\nimport kotlin.random.Random\n\n\n////////////////////////////////////////////////////////////////////////////////\n// Entry Methods\n////////////////////////////////////////////////////////////////////////////////\n\ntypealias CheckLogicInTask = () -> Unit\n\nfun CheckLogicInTask.toRunnable() = Runnable { this() }\n\ntypealias TaskRunner = () -> Future<*>\n\n/**\n * - create task immediately with input [CheckLogicInTask] parameter\n * - return task runner to run task later\n */\ntypealias TaskRunnerGenerator = (CheckLogicInTask) -> TaskRunner\n\nenum class CaptureTime {\n    TASK_CREATE,\n    TASK_RUN,\n}\n\n\nfun FunSpecRootScope.ttlFlowTest(\n    name: String,\n    captureTime: CaptureTime = CaptureTime.TASK_CREATE,\n    taskRunnerGenerator: TaskRunnerGenerator,\n) {\n    test(name) {\n        runTtlFlowTest(captureTime, taskRunnerGenerator)\n    }\n}\n\nval captureTimeByAgentRun =\n    if (noTtlAgentRun()) CaptureTime.TASK_CREATE\n    else CaptureTime.TASK_RUN\n\n////////////////////////////////////////////////////////////////////////////////\n// TTL Flow Tester\n////////////////////////////////////////////////////////////////////////////////\n\nprivate fun runTtlFlowTest(\n    captureTime: CaptureTime = CaptureTime.TASK_CREATE,\n    taskRunnerGenerator: TaskRunnerGenerator\n) {\n    TtlFlowTester(captureTime, taskRunnerGenerator).run()\n}\n\nprivate class TtlFlowTester(\n    private val captureTime: CaptureTime = CaptureTime.TASK_CREATE,\n    private val taskRunnerGenerator: TaskRunnerGenerator\n) {\n    fun run() {\n        register(::StringTtlCreateAtParentBeginAndRemoveImmediately)\n        register(::StringTtlCreateAtParentBegin.fill())\n\n        register(::DeepCopyTtlCreateAtParentBeginUnmodifiedInChild)\n        register(::DeepCopyTtlCreateAtParentBeginModifiedInChild)\n\n        compositeTtlFlow.beginInParent()\n\n        //////////////////////////////////////////////\n        // create task\n        //////////////////////////////////////////////\n        val task = taskRunnerGenerator(::checkInTask)\n\n        compositeTtlFlow.afterTaskCreatedInParent()\n\n        register(::StringTtlCreateAtParentAfterCreateTask.fill())\n\n        register(::DeepCopyTtlCreateAtParentAfterCreateTask)\n\n        //////////////////////////////////////////////\n        // start task\n        //////////////////////////////////////////////\n        val future: Future<*> = task()\n\n        compositeTtlFlow.afterTaskStartedInParent()\n\n        register(::StringTtlCreateAtParentAfterStartTask)\n\n        //////////////////////////////////////////////\n        // finish task\n        //////////////////////////////////////////////\n        future.getForTest()\n\n        compositeTtlFlow.afterTaskFinishedInParent()\n    }\n\n    private fun checkInTask() {\n        register(::StringTtlCreateAtChildBegin)\n        register(::DeepCopyTtlCreateAtChildBegin)\n\n        compositeTtlFlow.beginInChild()\n\n        compositeTtlFlow.endInChild()\n    }\n\n    private val compositeTtlFlow = CompositeTtlFlow()\n\n    private inline fun register(factory: () -> TtlFlow) {\n        val ttlFlow = factory()\n        compositeTtlFlow.register(ttlFlow)\n        ttlFlow.settingAfterConstruct()\n    }\n\n    private fun ((CaptureTime) -> TtlFlow).fill(): () -> TtlFlow = { this(captureTime) }\n}\n\n\nprivate interface TtlFlow {\n    fun settingAfterConstruct()\n\n    fun beginInParent()\n\n    fun afterTaskCreatedInParent()\n\n    fun afterTaskStartedInParent()\n\n    fun beginInChild()\n\n    fun endInChild()\n\n    fun afterTaskFinishedInParent()\n}\n\n/**\n * TTL instance create in parent thread when begin parent\n * and remove value immediately\n *\n * same as not set\n */\nprivate class StringTtlCreateAtParentBeginAndRemoveImmediately :\n    TransmittableThreadLocal<String>(), TtlFlow {\n    override fun settingAfterConstruct() {\n        set(\"init ${Random.nextLong()}\")\n    }\n\n    override fun beginInParent() {\n        remove()\n    }\n\n    override fun afterTaskCreatedInParent() {\n    }\n\n    override fun afterTaskStartedInParent() {\n    }\n\n    override fun beginInChild() {\n        get().shouldBeNull()\n    }\n\n    override fun endInChild() {\n        get().shouldBeNull()\n        set(Random.nextLong().toString())\n    }\n\n    override fun afterTaskFinishedInParent() {\n        get().shouldBeNull()\n    }\n}\n\n/**\n * TTL instance create in parent thread when begin parent thread\n */\nprivate class StringTtlCreateAtParentBegin(private val captureTime: CaptureTime) :\n    TransmittableThreadLocal<String>(), TtlFlow {\n\n    private val initValue = \"init ${Random.nextLong()}\"\n    private val modifiedValue = \"modified ${Random.nextLong()}\"\n\n    override fun settingAfterConstruct() {\n        set(initValue)\n    }\n\n    override fun beginInParent() {\n    }\n\n    override fun afterTaskCreatedInParent() {\n        get() shouldBe initValue\n        set(modifiedValue)\n    }\n\n    override fun afterTaskStartedInParent() {\n        get() shouldBe modifiedValue\n    }\n\n    override fun beginInChild() {\n        if (captureTime == CaptureTime.TASK_CREATE) {\n            get() shouldBe initValue\n        } else {\n            get() shouldBe modifiedValue\n        }\n    }\n\n    override fun endInChild() {\n        set(\"modified by child ${Random.nextLong()}\")\n    }\n\n    override fun afterTaskFinishedInParent() {\n        get() shouldBe modifiedValue\n    }\n}\n\n/**\n * TTL instance create in parent thread after create task\n */\nprivate class StringTtlCreateAtParentAfterCreateTask(\n    private val captureTime: CaptureTime\n) : TransmittableThreadLocal<String>(), TtlFlow {\n\n    private val initValue = \"init ${Random.nextLong()}\"\n\n    override fun settingAfterConstruct() {\n        set(initValue)\n    }\n\n    override fun beginInParent() {\n        fail(\"should never be called\")\n    }\n\n    override fun afterTaskCreatedInParent() {\n        fail(\"should never be called\")\n    }\n\n    override fun afterTaskStartedInParent() {\n        get() shouldBe initValue\n    }\n\n    override fun beginInChild() {\n        if (captureTime == CaptureTime.TASK_CREATE) {\n            get().shouldBeNull()\n        } else {\n            get() shouldBe initValue\n        }\n    }\n\n    override fun endInChild() {\n        set(\"modified by child ${Random.nextLong()}\")\n    }\n\n    override fun afterTaskFinishedInParent() {\n        get() shouldBe initValue\n    }\n}\n\n/**\n * TTL instance create in parent thread after start task\n */\nprivate class StringTtlCreateAtParentAfterStartTask : TransmittableThreadLocal<String>(), TtlFlow {\n    private val initValue = \"init ${Random.nextLong()}\"\n\n    override fun settingAfterConstruct() {\n        set(initValue)\n    }\n\n    override fun beginInParent() {\n        fail(\"should never be called\")\n    }\n\n    override fun afterTaskCreatedInParent() {\n        fail(\"should never be called\")\n    }\n\n    override fun afterTaskStartedInParent() {\n        fail(\"should never be called\")\n    }\n\n    override fun beginInChild() {\n        get().shouldBeNull()\n    }\n\n    override fun endInChild() {\n        set(\"modified by child ${Random.nextLong()}\")\n    }\n\n    override fun afterTaskFinishedInParent() {\n        get() shouldBe initValue\n    }\n}\n\n/**\n * TTL instance create in child thread when begin child task\n */\nprivate class StringTtlCreateAtChildBegin : TransmittableThreadLocal<String>(), TtlFlow {\n\n    private val initValue = \"init ${Random.nextLong()}\"\n\n    override fun settingAfterConstruct() {\n        set(initValue)\n    }\n\n    override fun beginInParent() {\n        fail(\"should never be called\")\n    }\n\n    override fun afterTaskCreatedInParent() {\n        fail(\"should never be called\")\n    }\n\n    override fun afterTaskStartedInParent() {\n    }\n\n    override fun beginInChild() {\n    }\n\n    override fun endInChild() {\n        get() shouldBe initValue\n    }\n\n    override fun afterTaskFinishedInParent() {\n        get().shouldBeNull()\n    }\n}\n\nprivate class DeepCopyTtlCreateAtParentBeginUnmodifiedInChild : TransmittableThreadLocal<Pojo?>(), TtlFlow {\n    override fun transmitteeValue(parentValue: Pojo?): Pojo? = parentValue?.copy()\n\n\n    private val initName = \"parent create unmodified in child ${Random.nextLong()}\"\n    private val initAge = Random.nextInt()\n\n    override fun settingAfterConstruct() {\n        set(Pojo(initName, initAge))\n    }\n\n    override fun beginInParent() {\n    }\n\n    override fun afterTaskCreatedInParent() {\n    }\n\n    override fun afterTaskStartedInParent() {\n    }\n\n    override fun beginInChild() {\n        get() shouldBe Pojo(initName, initAge)\n    }\n\n    override fun endInChild() {\n    }\n\n    override fun afterTaskFinishedInParent() {\n        get() shouldBe Pojo(initName, initAge)\n    }\n}\n\nprivate class DeepCopyTtlCreateAtParentBeginModifiedInChild : TransmittableThreadLocal<Pojo?>(), TtlFlow {\n    override fun transmitteeValue(parentValue: Pojo?): Pojo? = parentValue?.copy()\n\n\n    private val initName = \"parent create modified in child ${Random.nextLong()}\"\n    private val initAge = Random.nextInt()\n\n    override fun settingAfterConstruct() {\n        set(Pojo(initName, initAge))\n    }\n\n    override fun beginInParent() {\n    }\n\n    override fun afterTaskCreatedInParent() {\n    }\n\n    override fun afterTaskStartedInParent() {\n    }\n\n    override fun beginInChild() {\n        get() shouldBe Pojo(initName, initAge)\n        get()!!.name = \"modified in child ${Random.nextLong()}\"\n        get()!!.age++\n    }\n\n    override fun endInChild() {\n    }\n\n    override fun afterTaskFinishedInParent() {\n        get() shouldBe Pojo(initName, initAge)\n    }\n}\n\nprivate class DeepCopyTtlCreateAtParentAfterCreateTask : TransmittableThreadLocal<Pojo?>(), TtlFlow {\n    override fun transmitteeValue(parentValue: Pojo?): Pojo? = parentValue?.copy()\n\n    private val initName = \"parent create after create task ${Random.nextLong()}\"\n    private val initAge = Random.nextInt()\n\n    override fun settingAfterConstruct() {\n        set(Pojo(initName, initAge))\n    }\n\n    override fun beginInParent() {\n        fail(\"should never be called\")\n    }\n\n    override fun afterTaskCreatedInParent() {\n        fail(\"should never be called\")\n    }\n\n    override fun afterTaskStartedInParent() {\n    }\n\n    override fun beginInChild() {\n        get().shouldBeNull()\n    }\n\n    override fun endInChild() {\n    }\n\n    override fun afterTaskFinishedInParent() {\n        get() shouldBe Pojo(initName, initAge)\n    }\n}\n\nprivate class DeepCopyTtlCreateAtChildBegin : TransmittableThreadLocal<Pojo?>(), TtlFlow {\n    override fun transmitteeValue(parentValue: Pojo?): Pojo? = parentValue?.copy()\n\n    private val initName = \"create at child begin ${Random.nextLong()}\"\n    private val initAge = Random.nextInt()\n\n    override fun settingAfterConstruct() {\n        set(Pojo(initName, initAge))\n    }\n\n    override fun beginInParent() {\n        fail(\"should never be called\")\n    }\n\n    override fun afterTaskCreatedInParent() {\n        fail(\"should never be called\")\n\n    }\n\n    override fun afterTaskStartedInParent() {\n    }\n\n    override fun beginInChild() {\n        get() shouldBe Pojo(initName, initAge)\n    }\n\n    override fun endInChild() {\n    }\n\n    override fun afterTaskFinishedInParent() {\n        get().shouldBeNull()\n    }\n}\n\n\nprivate class CompositeTtlFlow : TtlFlow {\n    private val instances = CopyOnWriteArraySet<TtlFlow>()\n\n    fun register(ttlFlow: TtlFlow) {\n        instances.add(ttlFlow).shouldBeTrue()\n    }\n\n    override fun settingAfterConstruct() {\n        fail(\"should never be called\")\n    }\n\n    override fun beginInParent() {\n        for (ttl in instances.shuffled()) {\n            ttl.beginInParent()\n        }\n    }\n\n    override fun afterTaskCreatedInParent() {\n        for (ttl in instances.shuffled()) {\n            ttl.afterTaskCreatedInParent()\n        }\n    }\n\n    override fun afterTaskStartedInParent() {\n        for (ttl in instances.shuffled()) {\n            ttl.afterTaskStartedInParent()\n        }\n    }\n\n    override fun beginInChild() {\n        for (ttl in instances.shuffled()) {\n            ttl.beginInChild()\n        }\n    }\n\n    override fun endInChild() {\n        for (ttl in instances.shuffled()) {\n            ttl.endInChild()\n        }\n    }\n\n    override fun afterTaskFinishedInParent() {\n        for (ttl in instances.shuffled()) {\n            ttl.afterTaskFinishedInParent()\n        }\n    }\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n// TTL classes for test\n////////////////////////////////////////////////////////////////////////////////\n\nprivate data class Pojo(var name: String?, var age: Int)\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/ttl3/TtlRunnableTest.kt",
    "content": "package com.alibaba.ttl3\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.getForTest\nimport com.alibaba.shutdownForTest\nimport com.alibaba.ttlWrapIfNoTtlAgentRun\nimport io.kotest.assertions.throwables.shouldThrow\nimport io.kotest.core.spec.style.FunSpec\nimport io.kotest.matchers.collections.shouldBeEmpty\nimport io.kotest.matchers.collections.shouldContainInOrder\nimport io.kotest.matchers.collections.shouldHaveSize\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.string.shouldContain\nimport io.kotest.matchers.types.shouldBeSameInstanceAs\nimport io.kotest.matchers.types.shouldBeTypeOf\nimport java.util.concurrent.CompletableFuture\nimport java.util.concurrent.ExecutionException\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport kotlin.concurrent.thread\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass TtlRunnableTest : FunSpec({\n    lateinit var executorService: ExecutorService\n\n    beforeSpec {\n        executorService = Executors.newFixedThreadPool(3).also { expandThreadPool(it) }\n    }\n\n    afterSpec {\n        executorService.shutdownForTest()\n    }\n\n\n    ttlFlowTest(\"run in current thread\") { checkLogicInTask ->\n        val ttlRunnable = TtlRunnable.get(checkLogicInTask)!!\n\n        val taskRunner: TaskRunner = {\n            // run in the *current* thread\n            ttlRunnable.run()\n\n            CompletableFuture.completedFuture(null)\n        }\n        taskRunner\n    }\n\n    ttlFlowTest(\"async run by new thread\") { checkLogicInTask ->\n        val ttlRunnable = TtlRunnable.get(checkLogicInTask)!!\n\n        val taskRunner: TaskRunner = {\n            val future = CompletableFuture<Void>()\n            // run in new thread\n            thread {\n                ttlRunnable.run()\n                future.complete(null)\n            }\n            future\n        }\n        taskRunner\n    }\n\n    ttlFlowTest(\"async run by executor service\", captureTimeByAgentRun) { checkLogicInTask ->\n        val runnable: Runnable = checkLogicInTask.toRunnable().ttlWrapIfNoTtlAgentRun()\n\n        val taskRunner: TaskRunner = {\n            executorService.submit(runnable)\n        }\n        taskRunner\n    }\n\n    test(\"release ttl value reference after run\") {\n        val ttlRunnable = TtlRunnable.get({ }, true)!!\n\n        executorService.submit(ttlRunnable).getForTest().shouldBeNull()\n\n        val exception = shouldThrow<ExecutionException> {\n            executorService.submit(ttlRunnable).get()\n        }\n        exception.cause.shouldBeTypeOf<IllegalStateException>()\n        exception.message shouldContain \"TTL value reference is released after run!\"\n    }\n\n    test(\"get same\") {\n        val task = Runnable {}\n        val ttlRunnable = TtlRunnable.get(task)!!\n        ttlRunnable.runnable shouldBeSameInstanceAs task\n    }\n\n    test(\"get idempotent\") {\n        val task = TtlRunnable.get {}\n\n        shouldThrow<IllegalStateException> {\n            TtlRunnable.get(task)\n        }.message shouldContain \"Already TtlRunnable\"\n    }\n\n    test(\"get null input\") {\n        TtlRunnable.get(null).shouldBeNull()\n    }\n\n    test(\"gets\") {\n        val task1 = Runnable {}\n        val task2 = Runnable {}\n        val task3 = Runnable {}\n\n        val taskList = TtlRunnable.gets(listOf(task1, task2, null, task3))\n\n        taskList.shouldHaveSize(4)\n\n        taskList[0].shouldBeTypeOf<TtlRunnable>()\n        taskList[1].shouldBeTypeOf<TtlRunnable>()\n        taskList[2].shouldBeNull()\n        taskList[3].shouldBeTypeOf<TtlRunnable>()\n    }\n\n    test(\"unwrap\") {\n        TtlRunnable.unwrap(null).shouldBeNull()\n\n        val runnable = Runnable {}\n        val ttlRunnable = TtlRunnable.get(runnable)\n\n        TtlRunnable.unwrap(runnable) shouldBeSameInstanceAs runnable\n        TtlRunnable.unwrap(ttlRunnable) shouldBeSameInstanceAs runnable\n\n        TtlWrappers.unwrap(runnable) shouldBeSameInstanceAs runnable\n        TtlWrappers.unwrap(ttlRunnable) shouldBeSameInstanceAs runnable\n\n\n        TtlRunnable.unwraps(listOf(runnable)).shouldContainInOrder(runnable)\n        TtlRunnable.unwraps(listOf(ttlRunnable)).shouldContainInOrder(runnable)\n\n        TtlRunnable.unwraps(listOf(ttlRunnable, runnable)).shouldContainInOrder(runnable, runnable)\n        TtlRunnable.unwraps(null).shouldBeEmpty()\n    }\n})\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/ttl3/TtlTimerTaskTest.kt",
    "content": "package com.alibaba.ttl3\n\nimport io.kotest.assertions.throwables.shouldThrow\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport io.kotest.matchers.types.shouldBeSameInstanceAs\nimport io.kotest.matchers.types.shouldBeTypeOf\nimport java.util.*\n\n@Suppress(\"DEPRECATION\")\nclass TtlTimerTaskTest : AnnotationSpec() {\n    @Test\n    fun test_get() {\n        TtlTimerTask.get(null).shouldBeNull()\n\n        val timerTask = object : TimerTask() {\n            override fun run() {}\n        }\n\n        val ttlTimerTask = TtlTimerTask.get(timerTask)\n        ttlTimerTask.shouldBeTypeOf<TtlTimerTask>()\n\n\n        shouldThrow<IllegalStateException> {\n            TtlTimerTask.get(ttlTimerTask)\n        }.message shouldBe \"Already TtlTimerTask!\"\n    }\n\n    @Test\n    fun test_unwrap() {\n        TtlTimerTask.unwrap(null).shouldBeNull()\n\n        val timerTask = object : TimerTask() {\n            override fun run() {}\n        }\n\n        val ttlTimerTask = TtlTimerTask.get(timerTask)\n        TtlTimerTask.unwrap(timerTask) shouldBeSameInstanceAs timerTask\n        TtlTimerTask.unwrap(ttlTimerTask) shouldBeSameInstanceAs timerTask\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/user_api_test/ttl3/DisableIgnoreNullValueSemanticsTest.kt",
    "content": "package com.alibaba.user_api_test.ttl3\n\nimport com.alibaba.getForTest\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport java.util.concurrent.FutureTask\nimport java.util.concurrent.atomic.AtomicInteger\nimport kotlin.concurrent.thread\n\n/**\n * Test the \"Ignore-Null-Value Semantics\" of [TransmittableThreadLocal] from user code(different package)\n */\nclass DisableIgnoreNullValueSemanticsTest : AnnotationSpec() {\n    @Test\n    fun test_TTL_not_disableIgnoreNullValueSemantics_defaultTtlBehavior() {\n        val ttl = object : TransmittableThreadLocal<String?>() {\n            override fun initialValue(): String {\n                return \"init\"\n            }\n\n            override fun childValue(parentValue: String?): String {\n                return \"$parentValue + child\"\n            }\n        }\n\n        ttl.get() shouldBe \"init\"\n        ttl.set(null)\n        // DO NOT `ttl.get()` !\n        //   `get` operation will re-init the value of ThreadLocal\n\n        val task = FutureTask {\n            ttl.get()\n        }\n        thread { task.run() }.join()\n\n        // `get` operation will re-init the value of ThreadLocal !\n        ttl.get() shouldBe \"init\"\n        // \"Ignore-Null-Value Semantics\" will not transmit ThreadLocal with the null value,\n        // so the value in new thread is \"init\" value\n        ttl.get() shouldBe \"init\"\n\n        //////////////////////////////////////\n\n        val task2 = FutureTask {\n            ttl.get()\n        }\n        thread { task2.run() }.join()\n\n        ttl.get() shouldBe \"init\"\n        task2.getForTest() shouldBe \"init + child\"\n    }\n\n    @Test\n    fun test_TTL_not_disableIgnoreNullValueSemantics_defaultTtlBehavior_getSafe_ForNullInit() {\n        val count = AtomicInteger()\n\n        val ttl = object : TransmittableThreadLocal<String?>() {\n            override fun initialValue(): String? {\n                count.getAndIncrement()\n                return super.initialValue()\n            }\n\n            override fun childValue(parentValue: String?): String? {\n                count.getAndSet(1000)\n                return super.childValue(parentValue)\n            }\n        }\n\n        ttl.get().shouldBeNull()\n        count.get() shouldBe 1\n\n        ttl.set(null)\n        ttl.get().shouldBeNull()\n        count.get() shouldBe 2\n    }\n\n    @Test\n    fun test_TTL_disableIgnoreNullValueSemantics_sameAsThreadLocal() {\n        val ttl = object : TransmittableThreadLocal<String?>(true) {\n            override fun initialValue(): String {\n                return \"init\"\n            }\n\n            override fun childValue(parentValue: String?): String {\n                return \"$parentValue + child\"\n            }\n        }\n\n        ttl.get() shouldBe \"init\"\n        ttl.set(null)\n        ttl.get().shouldBeNull()\n\n        val task = FutureTask {\n            ttl.get()\n        }\n        thread { task.run() }.join()\n\n        ttl.get().shouldBeNull()\n        task.getForTest() shouldBe \"null + child\"\n\n        //////////////////////////////////////\n\n        val task2 = FutureTask {\n            ttl.get()\n        }\n        thread { task2.run() }.join()\n\n        ttl.get().shouldBeNull()\n        task.getForTest() shouldBe \"null + child\"\n    }\n\n    @Test\n    fun test_InheritableThreadLocal() {\n        val ttl = object : InheritableThreadLocal<String?>() {\n            override fun initialValue(): String {\n                return \"init\"\n            }\n\n            override fun childValue(parentValue: String?): String {\n                return \"$parentValue + child\"\n            }\n        }\n\n        ttl.get() shouldBe \"init\"\n        ttl.set(null)\n        ttl.get().shouldBeNull()\n\n        val task = FutureTask {\n            ttl.get()\n        }\n        thread { task.run() }.join()\n\n        ttl.get().shouldBeNull()\n        task.getForTest() shouldBe \"null + child\"\n\n        //////////////////////////////////////\n\n        val task2 = FutureTask {\n            ttl.get()\n        }\n        thread { task2.run() }.join()\n\n        ttl.get().shouldBeNull()\n        task.getForTest() shouldBe \"null + child\"\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/user_api_test/ttl3/TransmittableThreadLocal_Transmitter_UserTest.kt",
    "content": "package com.alibaba.user_api_test.ttl3\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.getForTest\nimport com.alibaba.shutdownForTest\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport com.alibaba.ttl3.transmitter.Transmitter\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport java.util.*\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\n\n/**\n * Test [Transmitter] from user code(different package)\n */\nclass TransmittableThreadLocal_Transmitter_UserTest : AnnotationSpec() {\n\n    @Test\n    fun test_crr() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(parentValue)\n\n        val capture = Transmitter.capture()\n\n        val future = executorService.submit {\n            ttl.set(childValue)\n\n            val backup = Transmitter.replay(capture)\n\n            ttl.get() shouldBe parentValue\n\n            Transmitter.restore(backup)\n\n            ttl.get() shouldBe childValue\n        }\n\n        ttl.get() shouldBe parentValue\n\n        future.getForTest()\n\n        ttl.get() shouldBe parentValue\n    }\n\n    @Test\n    fun test_clear_restore() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(parentValue)\n\n        val future = executorService.submit {\n            ttl.set(childValue)\n\n            val backup = Transmitter.clear()\n\n\n            ttl.get().shouldBeNull()\n\n            Transmitter.restore(backup)\n\n            ttl.get() shouldBe childValue\n        }\n\n        ttl.get() shouldBe parentValue\n\n        future.getForTest()\n\n        ttl.get() shouldBe parentValue\n    }\n\n    @Test\n    fun test_runSupplierWithCaptured() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(parentValue)\n\n        val capture = Transmitter.capture()\n\n        val future = executorService.submit {\n            ttl.set(\"child\")\n            Transmitter.runSupplierWithCaptured(capture) {\n                ttl.get() shouldBe parentValue\n                ttl.get()\n            }\n        }\n\n        ttl.get() shouldBe parentValue\n\n        future.getForTest()\n\n        ttl.get() shouldBe parentValue\n    }\n\n    @Test\n    fun test_runSupplierWithClear() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(parentValue)\n\n        val future = executorService.submit {\n            ttl.set(\"child\")\n            Transmitter.runSupplierWithClear {\n                ttl.get().shouldBeNull()\n                ttl.get()\n            }\n        }\n\n        ttl.get() shouldBe parentValue\n\n        future.getForTest()\n\n        ttl.get() shouldBe parentValue\n    }\n\n    @Test\n    fun test_runCallableWithCaptured() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(parentValue)\n\n        val capture = Transmitter.capture()\n\n        val future = executorService.submit {\n            ttl.set(\"child\")\n            try {\n                Transmitter.runCallableWithCaptured(capture) {\n                    ttl.get() shouldBe parentValue\n                    ttl.get()\n                }\n            } catch (e: Exception) {\n                throw RuntimeException(e)\n            }\n        }\n\n        ttl.get() shouldBe parentValue\n\n        future.getForTest()\n\n        ttl.get() shouldBe parentValue\n    }\n\n    @Test\n    fun test_runCallableWithClear() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(parentValue)\n\n        val future = executorService.submit {\n            ttl.set(\"child\")\n            try {\n                Transmitter.runCallableWithClear {\n                    ttl.get().shouldBeNull()\n                    ttl.get()\n                }\n            } catch (e: Exception) {\n                throw RuntimeException(e)\n            }\n        }\n\n        ttl.get() shouldBe parentValue\n\n        future.getForTest()\n\n        ttl.get() shouldBe parentValue\n    }\n\n    private val parentValue = \"parent: \" + Date()\n    private val childValue = \"child: \" + Date()\n    private lateinit var executorService: ExecutorService\n\n    @BeforeAll\n    fun beforeAll() {\n        executorService = Executors.newFixedThreadPool(3).also { expandThreadPool(it) }\n    }\n\n    @AfterAll\n    fun afterAll() {\n        executorService.shutdownForTest()\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/user_api_test/ttl3/TransmittableThreadLocal_Transmitter_registerTransmittee_UserTest.kt",
    "content": "package com.alibaba.user_api_test.ttl3\n\nimport com.alibaba.ttl3.transmitter.Transmittee\nimport com.alibaba.ttl3.transmitter.TransmitteeRegistry\nimport com.alibaba.ttl3.transmitter.Transmitter\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport io.mockk.*\n\n/**\n * Test [Transmitter] from user code(different package)\n */\nclass TransmittableThreadLocal_Transmitter_registerTransmittee_UserTest : AnnotationSpec() {\n    @Test\n    fun test_registerTransmittee_crr() {\n        // ========================================\n        // 0. mocks creation and stubbing\n        // ========================================\n        val transmittee = mockk<Transmittee<List<String>, Set<Int>>>()\n        @Suppress(\"UnusedEquals\", \"ReplaceCallWithBinaryOperator\")\n        excludeRecords {\n            transmittee.equals(any())\n            transmittee.hashCode()\n        }\n\n        every { transmittee.capture() } returns listOf(\"42\", \"43\")\n        every { transmittee.replay(listOf(\"42\", \"43\")) } returns setOf(42, 43)\n        every { transmittee.restore(setOf(42, 43)) } just Runs\n\n        try {\n            // ========================================\n            // 1. mock record(aka. invocation)\n            // ========================================\n            TransmitteeRegistry.registerTransmittee(transmittee).shouldBeTrue()\n\n            val captured = Transmitter.capture()\n            val backup = Transmitter.replay(captured)\n            Transmitter.restore(backup)\n\n            // ========================================\n            // 2. mock verification\n            // ========================================\n            verifySequence {\n                transmittee.capture()\n                transmittee.replay(any())\n                transmittee.restore(any())\n            }\n            confirmVerified(transmittee)\n        } finally {\n            TransmitteeRegistry.unregisterTransmittee(transmittee).shouldBeTrue()\n        }\n    }\n\n    @Test\n    fun test_registerTransmittee_clear_restore() {\n        // ========================================\n        // 0. mocks creation and stubbing\n        // ========================================\n        val transmittee = mockk<Transmittee<List<String>, Set<Int>>>()\n        @Suppress(\"UnusedEquals\", \"ReplaceCallWithBinaryOperator\")\n        excludeRecords {\n            transmittee.equals(any())\n            transmittee.hashCode()\n        }\n\n        every { transmittee.clear() } returns setOf(42, 43)\n        every { transmittee.restore(setOf(42, 43)) } just Runs\n\n        try {\n            // ========================================\n            // 1. mock record(aka. invocation)\n            // ========================================\n            TransmitteeRegistry.registerTransmittee(transmittee).shouldBeTrue()\n\n            val backup = Transmitter.clear()\n            Transmitter.restore(backup)\n\n            // ========================================\n            // 2. mock verification\n            // ========================================\n            verifySequence {\n                transmittee.clear()\n                transmittee.restore(any())\n            }\n            confirmVerified(transmittee)\n        } finally {\n            TransmitteeRegistry.unregisterTransmittee(transmittee).shouldBeTrue()\n        }\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/user_api_test/ttl3/TransmittableThreadLocal_withInit_Null_Test.java",
    "content": "package com.alibaba.user_api_test.ttl3;\n\nimport com.alibaba.ttl3.TransmittableThreadLocal;\nimport org.junit.Test;\n\nimport java.util.function.Supplier;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\npublic class TransmittableThreadLocal_withInit_Null_Test {\n\n    @Test\n    public void test_null__withInitial() {\n        try {\n            TransmittableThreadLocal.<String>withInitial(null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"supplier is null\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void test_null__withInitialAndGenerator_2() {\n        try {\n            TransmittableThreadLocal.<String>withInitialAndGenerator(null, null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"supplier is null\", e.getMessage());\n        }\n\n        try {\n            TransmittableThreadLocal.withInitialAndGenerator((Supplier<String>) () -> null, null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"value generator is null\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void test_null__withInitialAndGenerator_3() {\n        try {\n            TransmittableThreadLocal.<String>withInitialAndGenerator(null, null, null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"supplier is null\", e.getMessage());\n        }\n\n        try {\n            TransmittableThreadLocal.withInitialAndGenerator((Supplier<String>) () -> null, null, null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"value generator for child value is null\", e.getMessage());\n        }\n\n        try {\n            TransmittableThreadLocal.withInitialAndGenerator((Supplier<String>) () -> null, parentValue -> null, null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"value generator for transmittee value is null\", e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "ttl-core/src/test/java/com/alibaba/user_api_test/ttl3/TransmittableThreadLocal_withInit_Test.kt",
    "content": "package com.alibaba.user_api_test.ttl3\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.getForTest\nimport com.alibaba.shutdownForTest\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport com.alibaba.ttl3.executor.TtlExecutors\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.nulls.shouldNotBeNull\nimport io.kotest.matchers.shouldBe\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport java.util.concurrent.atomic.AtomicInteger\nimport kotlin.concurrent.thread\n\nclass TransmittableThreadLocal_withInit_Test : AnnotationSpec() {\n\n    @Test\n    fun test_withInit() {\n        val ttl: TransmittableThreadLocal<Int> = TransmittableThreadLocal.withInitial { 42 }\n\n        ttl.shouldNotBeNull()\n        ttl.get() shouldBe 42\n\n        val atomicInteger = AtomicInteger(-1)\n        thread {\n            atomicInteger.set(ttl.get())\n        }.join()\n        atomicInteger.get() shouldBe 42\n\n        atomicInteger.set(-1)\n        executorService.submit {\n            atomicInteger.set(ttl.get())\n        }.getForTest()\n        atomicInteger.get() shouldBe 42\n    }\n\n    @Test\n    fun test_withInitialAndGenerator_2() {\n        val ttl = TransmittableThreadLocal.withInitialAndGenerator(\n            { 42 },\n            { it + 100 },\n        )\n        ttl.shouldNotBeNull()\n        ttl.get() shouldBe 42\n\n        val atomicInteger = AtomicInteger(-1)\n        thread {\n            atomicInteger.set(ttl.get())\n        }.join()\n        atomicInteger.get() shouldBe 142\n\n        atomicInteger.set(-1)\n        executorService.submit {\n            atomicInteger.set(ttl.get())\n        }.getForTest()\n        atomicInteger.get() shouldBe 142\n    }\n\n    @Test\n    fun test_withInitialAndGenerator_3() {\n        val ttl = TransmittableThreadLocal.withInitialAndGenerator(\n            { 42 },\n            { it + 100 },\n            { it + 1000 },\n        )\n        ttl.shouldNotBeNull()\n        ttl.get() shouldBe 42\n\n        val atomicInteger = AtomicInteger(-1)\n        thread {\n            atomicInteger.set(ttl.get())\n        }.join()\n        atomicInteger.get() shouldBe 142\n\n        atomicInteger.set(-1)\n        executorService.submit {\n            atomicInteger.set(ttl.get())\n        }.getForTest()\n        atomicInteger.get() shouldBe 1042\n    }\n\n\n    private lateinit var executorService: ExecutorService\n\n    @BeforeAll\n    fun beforeAll() {\n        executorService = Executors.newFixedThreadPool(3).let {\n            expandThreadPool(it)\n            TtlExecutors.getTtlExecutorService(it)!!\n        }\n    }\n\n    @AfterAll\n    fun afterAll() {\n        executorService.shutdownForTest()\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/sample-ttl-agent-extension-transformlet/README.md",
    "content": "# `TTL Agent`扩展`Transformlet`实现的示例工程\n\n## 扩展`Transformlet`的实现\n\n为了提供`TTL Agent`扩展`Transformlet`，包含2部分：\n\n1. `TTL Agent`扩展`Transformlet`的实现类：[`SampleExtensionTransformlet`](src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/transformlet/SampleExtensionTransformlet.java)。\n    - 这个示例`Transformlet`修改了类[`ToBeTransformedClass`](src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClass.java)的`toBeTransformedMethod`方法：在修改方法前插入一行代码，修改方法参数值乘以2（`$1 *= 2;`）。\n1. `TTL Agent`扩展`Transformlet`的配置文件：[`META-INF/ttl.agent.transformlets`](src/main/resources/META-INF/ttl.agent.transformlets)\n    - 配置文件的内容是 扩展`Transformlet`实现类的全类名。  \n      在这个示例工程是`com.alibaba.ttl.agent.extension_transformlet.sample.transformlet.SampleExtensionTransformlet`。\n    - `TTL Agent`会扫描`Class Path`上的`META-INF/ttl.agent.transformlets`文件，自动发现并启用这些扩展`Transformlet`。  \n      即只要将扩展`Transformlet`的依赖`Jar`引入到应用中就会自动生效。\n    - 这个扫描并自动加载生效与`JDK`的[`ServiceLoader`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/ServiceLoader.html)一样，只是使用不同的扩展配置文件。\n\n## 扩展`Transformlet`实现的注意点\n\n在`Transformlet`的实现逻辑中，**_不要_** 加载被`transform`的类 或是 做实例化，如\n\n- `ToBeTransformedClass.class`\n- `Class.forName(\"com.alibaba.ttl.agent.extension_transformlet.sample.biz.ToBeTransformedClass\")`\n- `new ToBeTransformedClass()`\n\n加载被`transform`的类会导致对该类的`transform`操作被跳过，也就是`Transformlet`失效了。\n\n## 扩展`Transformlet`的测试与生效验证\n\n单元测试类 在 [`ToBeTransformedClassTest`](src/test/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClassTest.java)。\n\n通过运行`Maven`单元测试验证扩展`Transformlet` `SampleExtensionTransformlet`是否生效：\n\n\n```bash\n# sample-ttl-agent-extension-transformlet 工程目录，执行\n\n# 1. 先 mvn install TTL lib\n(cd ../.. && mvn install -Dmaven.test.skip)\n\n# 2. 验证 扩展Transformlet SampleExtensionTransformlet 是否生效\nmvn test -Penable-TtlAgent-forTest\n# 更多输出TTL的Transform类操作的日志\nmvn test -Penable-TtlAgent-forTest -Penable-LogTransform-forTest\n```\n\n## 运行示例`SampleMain`\n\n可以通过`Java`命令行参数来运行示例`SampleMain`：\n\n```java\njava -javaagent:path/to/transmittable-thread-local-2.x.y.jar \\\n    -cp target/classes \\\n    com.alibaba.ttl.agent.extension_transformlet.sample.biz.SampleMain\n```\n\n通过脚本[`scripts/run.sh`](scripts/run.sh)快速上面命令行的运行。\n"
  },
  {
    "path": "ttl-integrations/sample-ttl-agent-extension-transformlet/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>com.alibaba.ttl3</groupId>\n\t<artifactId>sample-ttl-agent-extension-transformlet</artifactId>\n\t<version>1.0.0-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>${project.artifactId}</name>\n\n\t<properties>\n\t\t<maven.compiler.source>1.8</maven.compiler.source>\n\t\t<maven.compiler.target>${maven.compiler.source}</maven.compiler.target>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t\t<maven.deploy.skip>true</maven.deploy.skip>\n\t\t<maven.javadoc.skip>true</maven.javadoc.skip>\n\t\t<jacoco.skip>true</jacoco.skip>\n\n\t\t<ttl.version>3.x-SNAPSHOT</ttl.version>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>transmittable-thread-local</artifactId>\n\t\t\t<version>${ttl.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.13.2</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\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<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t\t<version>3.5.2</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t\t<version>3.3.1</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t\t<version>3.8.0</version>\n\t\t\t\t</plugin>\n\t\t\t\t<plugin>\n\t\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t\t<version>3.1.3</version>\n\t\t\t\t</plugin>\n\t\t\t</plugins>\n\t\t</pluginManagement>\n\t</build>\n\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>enable-TtlAgent-forTest</id>\n\t\t\t<properties>\n\t\t\t\t<surefire.ttl.agent.log.class.transform/>\n\t\t\t\t<surefire.verbose.class/>\n\t\t\t</properties>\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<configuration>\n\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\tproperty `com.alibaba:transmittable-thread-local:jar` is generated by maven-dependency-plugin\n\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t<argLine>\n\t\t\t\t\t\t\t\t${surefire.verbose.class}\n\t\t\t\t\t\t\t\t-javaagent:${com.alibaba:transmittable-thread-local:jar}=ttl.agent.logger:STDOUT\n\t\t\t\t\t\t\t\t${surefire.ttl.agent.log.class.transform}\n\t\t\t\t\t\t\t</argLine>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\tHow to get path to dependency jar with maven\n\t\t\t\t\t\t\thttps://stackoverflow.com/a/56396097/922688\n\t\t\t\t\t\t\tApache Maven Dependency Plugin – Introduction\n\t\t\t\t\t\t\thttps://maven.apache.org/plugins/maven-dependency-plugin/\n\t\t\t\t\t\t-->\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\t<version>3.8.1</version>\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<phase>initialize</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>properties</goal>\n\t\t\t\t\t\t\t\t</goals>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>enable-LogTransform-forTest</id>\n\t\t\t<properties>\n\t\t\t\t<surefire.ttl.agent.log.class.transform>-Dttl.agent.log.class.transform</surefire.ttl.agent.log.class.transform>\n\t\t\t</properties>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>enable-verboseClass-forTest</id>\n\t\t\t<properties>\n\t\t\t\t<surefire.verbose.class>-verbose:class</surefire.verbose.class>\n\t\t\t</properties>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>gen-code-cov</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<!-- https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables -->\n\t\t\t\t\t<name>env.CI</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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.jacoco</groupId>\n\t\t\t\t\t\t<artifactId>jacoco-maven-plugin</artifactId>\n\t\t\t\t\t\t<version>0.8.12</version>\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<goals>\n\t\t\t\t\t\t\t\t\t<goal>prepare-agent</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>report</id>\n\t\t\t\t\t\t\t\t<phase>test</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>report</goal>\n\t\t\t\t\t\t\t\t</goals>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "ttl-integrations/sample-ttl-agent-extension-transformlet/scripts/integration-test.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\n# adjust current dir to project dir\ncd \"$(dirname \"$(readlink -f \"$0\")\")/..\"\n\nTTL_ROOT_PROJECT_DIR=\"$(dirname \"$(readlink -f \"../\")\")\"\n\nsource \"$TTL_ROOT_PROJECT_DIR/scripts/common_build.sh\"\nsource \"$TTL_ROOT_PROJECT_DIR/scripts/prepare-jdk.sh\"\n\nfor jv in 8 11; do\n    switch_to_jdk \"$jv\"\n\n    headInfo \"test with JDK $JAVA_HOME\"\n\n    MVN_WITH_BASIC_OPTIONS test\n    MVN_WITH_BASIC_OPTIONS test -Penable-TtlAgent-forTest\ndone\n"
  },
  {
    "path": "ttl-integrations/sample-ttl-agent-extension-transformlet/scripts/run.sh",
    "content": "#!/bin/bash\nset -eEuo pipefail\n# adjust current dir to project dir\ncd \"$(dirname \"$(readlink -f \"$0\")\")/..\"\n\nTTL_ROOT_PROJECT_DIR=\"$(dirname \"$(readlink -f \"../\")\")\"\n\nsource \"$TTL_ROOT_PROJECT_DIR/scripts/common_build.sh\"\n\nttl_version=$(extractFirstElementValueFromPom version \"../../pom.xml\")\n\nreadonly ttl_agent_path=\"$TTL_ROOT_PROJECT_DIR/target/transmittable-thread-local-$ttl_version.jar\"\n\nmvn_ttl_lib() {\n    (\n        cd \"$TTL_ROOT_PROJECT_DIR\"\n        MVN_WITH_BASIC_OPTIONS -q -Dmaven.test.skip \"$@\"\n    )\n}\n\nif [ \"${1:-}\" != \"skipClean\" ]; then\n    mvn_ttl_lib clean package\n\n    # compile sample-ttl-agent-extension-transformlet\n    MVN_WITH_BASIC_OPTIONS -q clean compile\nelse\n    if [ ! -f \"$ttl_agent_path\" ]; then\n        mvn_ttl_lib package\n    fi\n\n    # compile sample-ttl-agent-extension-transformlet\n    MVN_WITH_BASIC_OPTIONS -q compile\nfi\n\nreadonly ttl_agent_options=\"-javaagent:$ttl_agent_path=ttl.agent.logger:STDOUT,ttl.agent.log.class.transform:true\"\n\nreadonly main_class=com.alibaba.ttl.agent.extension_transformlet.sample.biz.SampleMain\n\nlogAndRun \"$JAVA_HOME/bin/java\" -Duser.language=en -Duser.country=US \\\n    \"${ttl_agent_options}\" \\\n    -cp target/classes $main_class\n"
  },
  {
    "path": "ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/SampleMain.java",
    "content": "package com.alibaba.ttl.agent.extension_transformlet.sample.biz;\n\nimport com.alibaba.ttl.threadpool.agent.TtlAgent;\nimport com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo;\n\npublic class SampleMain {\n    /**\n     * @see ToBeTransformedClass#toBeTransformedMethod(int)\n     * @see com.alibaba.ttl.agent.extension_transformlet.sample.transformlet.SampleExtensionTransformlet#doTransform(ClassInfo)\n     */\n    public static void main(String[] args) throws Exception {\n        final ToBeTransformedClass instance = new ToBeTransformedClass();\n\n        System.out.println(\"========================================\");\n        if (TtlAgent.isTtlAgentLoaded()) {\n            System.out.println(\"Run WITH TTL Agent\");\n        } else {\n            System.out.println(\"Run Without TTL Agent\");\n        }\n        System.out.println(instance.toBeTransformedMethod(21));\n        System.out.println(\"========================================\");\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClass.java",
    "content": "package com.alibaba.ttl.agent.extension_transformlet.sample.biz;\n\npublic class ToBeTransformedClass {\n    public int toBeTransformedMethod(int input) {\n        return input;\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/java/com/alibaba/ttl/agent/extension_transformlet/sample/transformlet/SampleExtensionTransformlet.java",
    "content": "package com.alibaba.ttl.agent.extension_transformlet.sample.transformlet;\n\nimport com.alibaba.ttl.agent.extension_transformlet.sample.biz.ToBeTransformedClass;\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.CannotCompileException;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.CtClass;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.CtMethod;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.NotFoundException;\n\nimport java.io.IOException;\n\n/**\n * {@link TtlTransformlet} for {@link ToBeTransformedClass}.\n *\n * <B><I>Caution:</I></B><br>\n * MUST use string constant for class/method name!\n * <p>\n * MUST NOT use {@code Class<?> class = ToBeTransformedClass.class} to get the class to be transformed({@code ToBeTransformedClass}),\n * {@code ToBeTransformedClass.class} operation will force to load the class to be transformed,\n * and cause the Transformlet to <b>SKIP</b> the class transform!\n */\npublic class SampleExtensionTransformlet implements TtlTransformlet {\n    private static final Logger logger = Logger.getLogger(SampleExtensionTransformlet.class);\n\n    public static final String TO_BE_TRANSFORMED_CLASS_NAME = \"com.alibaba.ttl.agent.extension_transformlet.sample.biz.ToBeTransformedClass\";\n    public static final String TO_BE_TRANSFORMED_METHOD = \"toBeTransformedMethod\";\n\n    public void doTransform(ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException {\n        if (!classInfo.getClassName().equals(TO_BE_TRANSFORMED_CLASS_NAME)) return;\n\n        final CtClass ctClass = classInfo.getCtClass();\n        final CtMethod method = ctClass.getDeclaredMethod(TO_BE_TRANSFORMED_METHOD);\n\n        final String code = \"$1 *= 2;\";\n        method.insertBefore(code);\n        logger.info(\"[SampleExtensionTransformlet] insert code before method \" + TO_BE_TRANSFORMED_METHOD\n            + \" of class \" + method.getDeclaringClass().getName() + \": \" + code);\n\n        classInfo.setModified();\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/sample-ttl-agent-extension-transformlet/src/main/resources/META-INF/ttl.agent.transformlets",
    "content": "com.alibaba.ttl.agent.extension_transformlet.sample.transformlet.SampleExtensionTransformlet\n"
  },
  {
    "path": "ttl-integrations/sample-ttl-agent-extension-transformlet/src/test/java/com/alibaba/ttl/agent/extension_transformlet/sample/biz/ToBeTransformedClassTest.java",
    "content": "package com.alibaba.ttl.agent.extension_transformlet.sample.biz;\n\nimport com.alibaba.ttl.threadpool.agent.TtlAgent;\nimport org.junit.Test;\n\nimport java.util.Properties;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class ToBeTransformedClassTest {\n    @Test\n    public void test_method1() {\n        final ToBeTransformedClass instance = new ToBeTransformedClass();\n\n        System.out.println(\"========================================\");\n        if (TtlAgent.isTtlAgentLoaded()) {\n            System.out.println(\"Test **WITH** TTL Agent\");\n            assertEquals(42, instance.toBeTransformedMethod(21));\n        } else {\n            System.out.println(\"Test WITHOUT TTL Agent\");\n            assertEquals(21, instance.toBeTransformedMethod(21));\n        }\n        System.out.println(\"========================================\");\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/vertx3-ttl-integration/README-EN.md",
    "content": "#  Vertx 4 integration of TTL\n\n## 1. assure TTL context transmit in callback \n\n## 1.1 Decorate `io.vertx.core.Handler`\n\nUse [`TtlVertxHandler`](src/main/java/com/alibaba/ttl/integration/vertx3/TtlVertxHandler.java) to decorate `Handler`。\n\n## 1.2 Decorate `io.vertx.core.Future`\n\nAt present, `TTL` agent has decorated below `Vertx` callback components(`io.vertx.core.Future`) implementation:\n\n- `io.vertx.core.Future`\n- `io.vertx.core.impl.future.FutureImpl`\n- `io.vertx.core.http.impl.HttpClientImpl`\n- decoration implementation code is in [`VertxFutureTtlTransformlet.java`](src/main/java/com/alibaba/ttl/integration/vertx3/agent/transformlet/VertxFutureTtlTransformlet.java)。\n\nSample code：\n\n```java\nVertx vertx = Vertx.vertx();\n\n//build channel\nManagedChannel channel = VertxChannelBuilder\n  .forAddress(vertx, \"localhost\", 8080)\n  .usePlaintext()\n  .build();\n\n// set in parent thread\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\ncontext.set(\"value-set-in-parent\");\n\n//init stub\nio.grpc.stub.XXX stub = XXX.newVertxStub(channel);\nHelloRequest request = HelloRequest.newBuilder().setName(\"Julien\").build();\n\n//init handler\nHandler<AsyncResult<String>> handler = event -> {\n  // read in callback, value is \"value-set-in-parent\"\n  context.get();\n  if (event.succeeded()) {\n    //do something\n  } else {\n    // find exception\n  }\n};\n// extra work, create decorated TtlVertxHandler object\nTtlVertxHandler<AsyncResult<String>> ttlVertxHandler = TtlVertxHandler.get(handler);\n\n//send request\nstub.sayHello(request).onComplete(ttlVertxHandler);\n```\n## 2. assure TTL context transmit in eventbus\n\n### 2. decorate`java.lang.Runnable`\nUse [`TtlRunnable`](../../src/main/java/com/alibaba/ttl/TtlRunnable.java) to decorate`Runnable`。\n\n### 2.2 Decorate`io.netty.util.concurrent.SingleThreadEventExecutor`\n\n- decoration implementation code is in[`NettySingleThreadEventExecutorTtlTransformlet.java`](src/main/java/com/alibaba/ttl/integration/vertx3/agent/transformlet/NettySingleThreadEventExecutorTtlTransformlet.java)。\n\n"
  },
  {
    "path": "ttl-integrations/vertx3-ttl-integration/README.md",
    "content": "# Vertx 4的TTL集成\n\n## 1. 保证异步io回调中传递TTL值\n\n### 1.1修饰`io.vertx.core.Handler`\n\n使用[`TtlVertxHandler`](src/main/java/com/alibaba/ttl/integration/vertx3/TtlVertxHandler.java)来修饰传入的`Handler`。\n\n### 1.2 修饰`io.vertx.core.Future`\n\n修饰了的Vert.x执行器组件如下:\n- `io.vertx.core.Future`\n- `io.vertx.core.impl.future.FutureImpl`\n- `io.vertx.core.http.impl.HttpClientImpl`\n---\n- 修饰实现代码在[`VertxFutureTtlTransformlet.java`](src/main/java/com/alibaba/ttl/integration/vertx3/agent/transformlet/VertxFutureTtlTransformlet.java)。\n\n示例代码：\n\n```java\nVertx vertx = Vertx.vertx();\n\n//build channel\nManagedChannel channel = VertxChannelBuilder\n  .forAddress(vertx, \"localhost\", 8080)\n  .usePlaintext()\n  .build();\n\n// set in parent thread\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\ncontext.set(\"value-set-in-parent\");\n\n//init stub\nio.grpc.stub.XXX stub = XXX.newVertxStub(channel);\nHelloRequest request = HelloRequest.newBuilder().setName(\"Julien\").build();\n\n//init handler\nHandler<AsyncResult<String>> handler = event -> {\n  // read in callback, value is \"value-set-in-parent\"\n  context.get();\n  if (event.succeeded()) {\n    //do something\n  } else {\n    // find exception\n  }\n};\n// extra work, create decorated TtlVertxHandler object\nTtlVertxHandler<AsyncResult<String>> ttlVertxHandler = TtlVertxHandler.get(handler);\n\n//send request\nstub.sayHello(request).onComplete(ttlVertxHandler);\n```\n\n    \n## 2. 保证`eventbus`上传递TTL值\n\n### 2.1修饰`java.lang.Runnable`\n使用[`TtlRunnable`](../../src/main/java/com/alibaba/ttl/TtlRunnable.java)来修饰传入的`Runnable`。\n\n### 2.2 修饰`io.netty.util.concurrent.SingleThreadEventExecutor`\n\n修饰实现代码在[`NettySingleThreadEventExecutorTtlTransformlet.java`](src/main/java/com/alibaba/ttl/integration/vertx3/agent/transformlet/NettySingleThreadEventExecutorTtlTransformlet.java)。\n"
  },
  {
    "path": "ttl-integrations/vertx3-ttl-integration/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.ttl3</groupId>\n\t\t<artifactId>ttl3-parent</artifactId>\n\t\t<version>3.x-SNAPSHOT</version>\n\t\t<relativePath>../../pom.xml</relativePath>\n\t</parent>\n\n\t<artifactId>vertx3-ttl-integration</artifactId>\n\t<version>0.1.0-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>${project.artifactId}</name>\n\t<description>TTL integration for vert.x 3</description>\n\t<url>https://github.com/alibaba/transmittable-thread-local/tree/master/ttl-integrations/vertx3-ttl-integration</url>\n\t<inceptionYear>2021</inceptionYear>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache 2</name>\n\t\t\t<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t\t<comments>A business-friendly OSS license</comments>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<connection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</connection>\n\t\t<developerConnection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</developerConnection>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t</scm>\n\t<issueManagement>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/issues</url>\n\t\t<system>GitHub Issues</system>\n\t</issueManagement>\n\t<ciManagement>\n\t\t<system>GitHub Actions</system>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/actions</url>\n\t</ciManagement>\n\n\t<properties>\n\t\t<maven.deploy.skip>true</maven.deploy.skip>\n\n\t\t<ttl.integration.test.skip>true</ttl.integration.test.skip>\n\t\t<skipTests>${ttl.integration.test.skip}</skipTests>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>io.vertx</groupId>\n\t\t\t<artifactId>vertx-core</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.netty</groupId>\n\t\t\t<artifactId>netty-all</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>transmittable-thread-local</artifactId>\n\t\t\t<version>${project.parent.version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.netty</groupId>\n\t\t\t\t<artifactId>netty-bom</artifactId>\n\t\t\t\t<version>4.1.84.Final</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>io.vertx</groupId>\n\t\t\t\t<artifactId>vertx-stack-depchain</artifactId>\n\t\t\t\t<version>3.9.13</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<profiles>\n\t\t<profile>\n\t\t\t<id>enable-TtlAgent-forTest</id>\n\t\t\t<properties>\n\t\t\t\t<surefire.ttl.agent.log.class.transform/>\n\t\t\t\t<surefire.verbose.class/>\n\t\t\t</properties>\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<configuration>\n\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\tproperty `com.alibaba:transmittable-thread-local:jar` is generated by maven-dependency-plugin\n\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t<argLine>\n\t\t\t\t\t\t\t\t${surefire.verbose.class}\n\t\t\t\t\t\t\t\t-javaagent:${com.alibaba:transmittable-thread-local:jar}=ttl.agent.logger:STDOUT\n\t\t\t\t\t\t\t\t${surefire.ttl.agent.log.class.transform}\n\t\t\t\t\t\t\t</argLine>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\tHow to get path to dependency jar with maven\n\t\t\t\t\t\t\thttps://stackoverflow.com/a/56396097/922688\n\t\t\t\t\t\t\tApache Maven Dependency Plugin – Introduction\n\t\t\t\t\t\t\thttps://maven.apache.org/plugins/maven-dependency-plugin/\n\t\t\t\t\t\t-->\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\t<version>3.8.1</version>\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<phase>initialize</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>properties</goal>\n\t\t\t\t\t\t\t\t</goals>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>enable-LogTransform-forTest</id>\n\t\t\t<properties>\n\t\t\t\t<surefire.ttl.agent.log.class.transform>-Dttl.agent.log.class.transform</surefire.ttl.agent.log.class.transform>\n\t\t\t</properties>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>enable-verboseClass-forTest</id>\n\t\t\t<properties>\n\t\t\t\t<surefire.verbose.class>-verbose:class</surefire.verbose.class>\n\t\t\t</properties>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "ttl-integrations/vertx3-ttl-integration/src/main/java/com/alibaba/ttl/integration/vertx3/TtlVertxHandler.java",
    "content": "package com.alibaba.ttl.integration.vertx3;\n\nimport com.alibaba.ttl.spi.TtlAttachments;\nimport com.alibaba.ttl.spi.TtlAttachmentsDelegate;\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport io.vertx.core.Handler;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.*;\n\n/**\n * {@link TtlVertxHandler} decorate {@link Handler}, so as to get {@link com.alibaba.ttl.TransmittableThreadLocal}\n * and transmit it to the time of {@link Handler} execution,\n * needed when use {@link Handler} to {@link io.vertx.core.Future}.\n * <p>\n * we will capture ttl value in another thread by modify {@link io.netty.util.concurrent.SingleThreadEventExecutor#execute(Runnable)},\n * but we can not capture the ttl value which we expect in callback of identical thread.\n * the reason of above issue is some async io callback was invoked by the\n * {@link io.netty.channel.nio.NioEventLoop#run()} rather than the {@link com.alibaba.ttl.TtlRunnable#run()}\n *\n * @author tk (305809299 at qq dot com)\n * @see io.vertx.core.Future\n * @see io.netty.channel.nio.NioEventLoop#run()\n * @see io.netty.channel.nio.NioEventLoop#processSelectedKeys()\n */\npublic class TtlVertxHandler<E> implements Handler<E>, TtlWrapper<Handler<E>>, TtlEnhanced, TtlAttachments {\n    private final AtomicReference<Object> capturedRef;\n    private final Handler<E> handler;\n    private final boolean releaseTtlValueReferenceAfterRun;\n\n    private TtlVertxHandler(@NonNull Handler<E> handler, boolean releaseTtlValueReferenceAfterRun) {\n        this.capturedRef = new AtomicReference<>(capture());\n        this.handler = handler;\n        this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;\n    }\n\n    /**\n     * wrap method {@link Handler#handle(Object)}.\n     */\n    @Override\n    public void handle(E event) {\n        final Object captured = capturedRef.get();\n        if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {\n            throw new IllegalStateException(\"TTL value reference is released after run!\");\n        }\n\n        final Object backup = replay(captured);\n        try {\n            handler.handle(event);\n        } finally {\n            restore(backup);\n        }\n    }\n\n    /**\n     * return original/unwrapped {@link Handler}.\n     */\n    @NonNull\n    public Handler<E> getHandler() {\n        return unwrap();\n    }\n\n    /**\n     * unwrap to original/unwrapped {@link Handler}.\n     *\n     * @see com.alibaba.ttl.TtlUnwrap#unwrap(Object)\n     */\n    @NonNull\n    @Override\n    public Handler<E> unwrap() {\n        return handler;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass()) {\n            return false;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        TtlVertxHandler<E> that = (TtlVertxHandler<E>) o;\n\n        return handler.equals(that.handler);\n    }\n\n    @Override\n    public int hashCode() {\n        return handler.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + handler.toString();\n    }\n\n    /**\n     * Factory method, wrap input {@link Handler} to {@link TtlVertxHandler}.\n     *\n     * @param handler input {@link Handler}. if input is {@code null}, return {@code null}.\n     * @return Wrapped {@link Handler}\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already.\n     */\n    @Nullable\n    public static <T> TtlVertxHandler<T> get(@Nullable Handler<T> handler) {\n        return get(handler, false, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link Handler} to {@link TtlVertxHandler}.\n     *\n     * @param handler                          input {@link Handler}. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlVertxHandler} is referred.\n     * @return Wrapped {@link Handler}\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already.\n     */\n    @Nullable\n    public static <T> TtlVertxHandler<T> get(@Nullable Handler<T> handler, boolean releaseTtlValueReferenceAfterRun) {\n        return get(handler, releaseTtlValueReferenceAfterRun, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link Handler} to {@link TtlVertxHandler}.\n     *\n     * @param handler                          input {@link Handler}. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlVertxHandler} is referred.\n     * @param idempotent                       is idempotent mode or not. if {@code true}, just return input {@link Handler} when it's {@link TtlVertxHandler},\n     *                                         otherwise throw {@link IllegalStateException}.\n     *                                         <B><I>Caution</I></B>: {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return Wrapped {@link Handler}\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already and not idempotent.\n     */\n    @Nullable\n    public static <T> TtlVertxHandler<T> get(@Nullable Handler<T> handler, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {\n        if (handler == null) {\n            return null;\n        }\n\n        if (handler instanceof TtlEnhanced) {\n            // avoid redundant decoration, and ensure idempotency\n            if (idempotent) {\n                return (TtlVertxHandler<T>) handler;\n            } else {\n                throw new IllegalStateException(\"Already TtlVertxHandler!\");\n            }\n        }\n        return new TtlVertxHandler<>(handler, releaseTtlValueReferenceAfterRun);\n    }\n\n    /**\n     * wrap input {@link Handler} Collection to {@link TtlVertxHandler} Collection.\n     *\n     * @param tasks task to be wrapped. if input is {@code null}, return {@code null}.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already.\n     */\n    @NonNull\n    public static <T> List<TtlVertxHandler<T>> gets(@Nullable Collection<? extends Handler<T>> tasks) {\n        return gets(tasks, false, false);\n    }\n\n    /**\n     * wrap input {@link Handler} Collection to {@link TtlVertxHandler} Collection.\n     *\n     * @param tasks                            task to be wrapped. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlVertxHandler} is referred.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already.\n     */\n    @NonNull\n    public static <T> List<TtlVertxHandler<T>> gets(@Nullable Collection<? extends Handler<T>> tasks, boolean releaseTtlValueReferenceAfterRun) {\n        return gets(tasks, releaseTtlValueReferenceAfterRun, false);\n    }\n\n    /**\n     * wrap input {@link Handler} Collection to {@link TtlVertxHandler} Collection.\n     *\n     * @param tasks                            task to be wrapped. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlVertxHandler} is referred.\n     * @param idempotent                       is idempotent mode or not. if {@code true}, just return input {@link Handler} when it's {@link TtlVertxHandler},\n     *                                         otherwise throw {@link IllegalStateException}.\n     *                                         <B><I>Caution</I></B>: {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already and not idempotent.\n     */\n    @NonNull\n    public static <T> List<TtlVertxHandler<T>> gets(@Nullable Collection<? extends Handler<T>> tasks, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {\n        if (tasks == null) {\n            return Collections.emptyList();\n        }\n\n        List<TtlVertxHandler<T>> copy = new ArrayList<>();\n        for (Handler<T> task : tasks) {\n            copy.add(TtlVertxHandler.get(task, releaseTtlValueReferenceAfterRun, idempotent));\n        }\n        return copy;\n    }\n\n    /**\n     * Unwrap {@link TtlVertxHandler} to the original/underneath one.\n     * <p>\n     * this method is {@code null}-safe, when input {@code Function} parameter is {@code null}, return {@code null};\n     * if input {@code Function} parameter is not a {@link TtlVertxHandler} just return input {@code Function}.\n     * <p>\n     * so {@code TtlVertxHandler.unwrap(TtlVertxHandler.get(function))} will always return the same input {@code function} object.\n     *\n     * @see #handle(Object)\n     * @see com.alibaba.ttl.TtlUnwrap#unwrap(Object)\n     */\n    @Nullable\n    public static <T> Handler<T> unwrap(@Nullable Handler<T> handler) {\n        if (!(handler instanceof TtlVertxHandler)) {\n            return handler;\n        } else {\n            return ((TtlVertxHandler<T>) handler).getHandler();\n        }\n    }\n\n    /**\n     * Unwrap {@link TtlVertxHandler} to the original/underneath one for collection.\n     * <p>\n     * Invoke {@link #unwrap(Handler)} for each element in input collection.\n     * <p>\n     * This method is {@code null}-safe, when input {@code Handler} parameter collection is {@code null}, return a empty list.\n     *\n     * @see #gets(Collection)\n     * @see #unwrap(Handler)\n     */\n    @NonNull\n    public static <T> List<Handler<T>> unwraps(@Nullable Collection<? extends Handler<T>> tasks) {\n        if (tasks == null) {\n            return Collections.emptyList();\n        }\n\n        List<Handler<T>> copy = new ArrayList<>();\n        for (Handler<T> task : tasks) {\n            if (!(task instanceof TtlVertxHandler)) {\n                copy.add(task);\n            } else {\n                copy.add(((TtlVertxHandler<T>) task).getHandler());\n            }\n        }\n        return copy;\n    }\n\n    private final TtlAttachmentsDelegate ttlAttachment = new TtlAttachmentsDelegate();\n\n    /**\n     * see {@link TtlAttachments#setTtlAttachment(String, Object)}\n     */\n    @Override\n    public void setTtlAttachment(@NonNull String key, Object value) {\n        ttlAttachment.setTtlAttachment(key, value);\n    }\n\n    /**\n     * see {@link TtlAttachments#getTtlAttachment(String)}\n     */\n    @Override\n    public <T> T getTtlAttachment(@NonNull String key) {\n        return ttlAttachment.getTtlAttachment(key);\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/vertx3-ttl-integration/src/main/java/com/alibaba/ttl/integration/vertx3/agent/transformlet/NettySingleThreadEventExecutorTtlTransformlet.java",
    "content": "package com.alibaba.ttl.integration.vertx3.agent.transformlet;\n\nimport com.alibaba.ttl.threadpool.agent.transformlet.helper.AbstractExecutorTtlTransformlet;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * {@link com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet}\n * for {@link io.netty.util.concurrent.SingleThreadEventExecutor}.\n *\n * @author tk (305809299 at qq dot com)\n * @see io.netty.util.concurrent.SingleThreadEventExecutor\n * @see io.vertx.core.eventbus.EventBus\n * @see io.vertx.core.impl.EventLoopContext\n * @see io.vertx.core.eventbus.Message\n */\npublic final class NettySingleThreadEventExecutorTtlTransformlet extends AbstractExecutorTtlTransformlet {\n\n    private static Set<String> getExecutorClassNames() {\n        Set<String> executorClassNames = new HashSet<>();\n\n        executorClassNames.add(\"io.netty.util.concurrent.SingleThreadEventExecutor\");\n\n        return executorClassNames;\n    }\n\n    public NettySingleThreadEventExecutorTtlTransformlet() {\n        super(getExecutorClassNames(), false);\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/vertx3-ttl-integration/src/main/java/com/alibaba/ttl/integration/vertx3/agent/transformlet/VertxFutureTtlTransformlet.java",
    "content": "package com.alibaba.ttl.integration.vertx3.agent.transformlet;\n\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.CannotCompileException;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.CtClass;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.CtMethod;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.NotFoundException;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport static com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.signatureOfMethod;\n\n/**\n * {@link TtlTransformlet} for {@link io.vertx.core.Future}.\n *\n * @author tk (305809299 at qq dot com)\n * @see com.alibaba.ttl.integration.vertx3.TtlVertxHandler\n * @see io.vertx.core.Future\n * @see io.vertx.core.Handler\n */\npublic class VertxFutureTtlTransformlet implements TtlTransformlet {\n    private static final Logger logger = Logger.getLogger(VertxFutureTtlTransformlet.class);\n\n    private static final String HANDLER_CLASS_NAME = \"io.vertx.core.Handler\";\n    private static final String TTL_HANDLER_CLASS_NAME = \"com.alibaba.ttl.integration.vertx3.TtlVertxHandler\";\n    private static final String FUTURE_CLASS_NAME = \"io.vertx.core.Future\";\n    private static final String HTTP_CLIENT_CLASS_NAME = \"io.vertx.core.http.impl.HttpClientImpl\";\n    private static final String DNS_CLIENT_CLASS_NAME = \"io.vertx.core.dns.impl.DnsClientImpl\";\n    private static final String VERTX_IMPL_CLASS_NAME = \"io.vertx.core.impl.VertxImpl\";\n    private static final String FUTURE_IMPL_CLASS_NAME = \"io.vertx.core.impl.future.FutureImpl\";\n\n    private static final Set<String> TO_BE_TRANSFORMED_CLASS_NAMES = new HashSet<>();\n\n    static {\n        TO_BE_TRANSFORMED_CLASS_NAMES.add(FUTURE_CLASS_NAME);\n        TO_BE_TRANSFORMED_CLASS_NAMES.add(FUTURE_IMPL_CLASS_NAME);\n        TO_BE_TRANSFORMED_CLASS_NAMES.add(HTTP_CLIENT_CLASS_NAME);\n        TO_BE_TRANSFORMED_CLASS_NAMES.add(VERTX_IMPL_CLASS_NAME);\n    }\n\n    @Override\n    public void doTransform(@NonNull ClassInfo classInfo) throws CannotCompileException, NotFoundException, IOException {\n        final CtClass clazz = classInfo.getCtClass();\n        if (TO_BE_TRANSFORMED_CLASS_NAMES.contains(classInfo.getClassName())) {\n            for (CtMethod method : clazz.getDeclaredMethods()) {\n                updateSetHandlerMethodsOfFutureClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(method);\n            }\n            classInfo.setModified();\n        }\n    }\n\n    private void updateSetHandlerMethodsOfFutureClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(CtMethod method) throws NotFoundException, CannotCompileException {\n        final int modifiers = method.getModifiers();\n        if (!checkMethodNeedToBeDecorated(modifiers)) {\n            return;\n        }\n\n        CtClass[] parameterTypes = method.getParameterTypes();\n        StringBuilder insertCode = new StringBuilder();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            final String paramTypeName = parameterTypes[i].getName();\n            if (HANDLER_CLASS_NAME.equals(paramTypeName)) {\n                String code = String.format(\n                    // decorate to TTL wrapper,\n                    // and then set AutoWrapper attachment/Tag\n                    \"$%d = %s.get($%1$d, false, true);\"\n                        + \"%n    com.alibaba.ttl.spi.TtlAttachmentsDelegate.setAutoWrapperAttachment($%1$d);\",\n                    i + 1, TTL_HANDLER_CLASS_NAME);\n                logger.info(\"insert code before method \" + signatureOfMethod(method) + \" of class \" + method.getDeclaringClass().getName() + \":\\n\" + code);\n                insertCode.append(code);\n            }\n        }\n        if (insertCode.length() > 0) method.insertBefore(insertCode.toString());\n    }\n\n    private boolean checkMethodNeedToBeDecorated(int modifiers) {\n        return Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && !Modifier.isAbstract(modifiers);\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/vertx3-ttl-integration/src/main/resources/META-INF/ttl.agent.transformlets",
    "content": "com.alibaba.ttl.integration.vertx3.agent.transformlet.NettySingleThreadEventExecutorTtlTransformlet\ncom.alibaba.ttl.integration.vertx3.agent.transformlet.VertxFutureTtlTransformlet\n"
  },
  {
    "path": "ttl-integrations/vertx3-ttl-integration/src/test/java/com/alibaba/ttl/integration/vertx3/VertxTransformletTest.java",
    "content": "package com.alibaba.ttl.integration.vertx3;\n\nimport com.alibaba.ttl.TransmittableThreadLocal;\nimport com.alibaba.ttl.threadpool.agent.TtlAgent;\nimport io.vertx.core.Vertx;\nimport io.vertx.core.eventbus.DeliveryOptions;\nimport org.junit.Test;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\n/**\n * @author tk (soulmate.tangk at gmail dot com)\n */\npublic class VertxTransformletTest {\n    @Test\n    public void testTransmitThreadLocal_InEventbus() throws Exception {\n        final TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>();\n        final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();\n\n        final String transmittedData = \"transmitted_data\";\n        final String inheritedData = \"inherited_data_ttl\";\n        final String message = \"message_42\";\n\n        final Vertx vertx = Vertx.vertx();\n        final String address = \"consumer\";\n\n        vertx.eventBus().consumer(address, msg -> {\n            // be executed in netty event loop thread\n            System.out.println(\"========================================\");\n            assertEquals(message, msg.body());\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                System.out.println(\"Test **WITH** TTL Agent\");\n                assertEquals(transmittedData, transmittableThreadLocal.get());\n            } else {\n                System.out.println(\"Test WITHOUT TTL Agent\");\n                assertNull(transmittableThreadLocal.get());\n            }\n\n            // InheritableThreadLocal is always null\n            assertNull(inheritableThreadLocal.get());\n\n            System.out.println(\"========================================\");\n\n            msg.reply(message);\n        });\n\n        transmittableThreadLocal.set(transmittedData);\n        inheritableThreadLocal.set(inheritedData);\n\n        // delivery message\n        final DeliveryOptions deliveryOptions = new DeliveryOptions();\n        deliveryOptions.setSendTimeout(1000);\n        vertx.eventBus().send(address, message, deliveryOptions, event -> {\n            System.out.println(\"receive reply message:\" + event.result().body());\n        });\n    }\n\n    @Test\n    public void testCallbackInHttpClient() throws Exception {\n        final TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>();\n        final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();\n        final String transmittedData = \"transmitted_data_ttl\";\n        final String inheritedData = \"inherited_data_ttl\";\n\n        final Vertx vertx = Vertx.vertx();\n\n        //set value after eventLoop thread was created\n        transmittableThreadLocal.set(transmittedData);\n        inheritableThreadLocal.set(inheritedData);\n\n        vertx.createHttpClient().get(80, \"bing.com\", \"/\", event -> {\n            System.out.println(\"receive msg:\" + event.statusCode());\n            System.out.println(\"===================callback=====================\");\n            event.bodyHandler(body -> {\n                System.out.println(\"receive response body: \" + body.toString(UTF_8));\n            });\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                System.out.println(\"Test **WITH** TTL Agent\");\n                assertEquals(transmittedData, transmittableThreadLocal.get());\n                assertNull(inheritableThreadLocal.get());\n            } else {\n                System.out.println(\"Test WITHOUT TTL Agent\");\n                assertNull(transmittableThreadLocal.get());\n                assertNull(inheritableThreadLocal.get());\n            }\n\n            System.out.println(\"===================callback=====================\");\n        }).end();\n\n        //wait for callback\n        Thread.sleep(2000);\n    }\n\n    @Test\n    public void testCallbackInVertxImpl() throws Exception {\n        final TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>();\n        final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();\n        final String transmittedData = \"transmitted_data_ttl\";\n        final String inheritedData = \"inherited_data_ttl\";\n        final String messageReplyInBlockingCode = \"messageReplyInBlockingCode___\";\n\n        final Vertx vertx = Vertx.vertx();\n\n        //set value after eventLoop thread was created\n        transmittableThreadLocal.set(transmittedData);\n        inheritableThreadLocal.set(inheritedData);\n\n        vertx.executeBlocking(a -> {\n            try {\n                Thread.sleep(1000);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            a.complete(messageReplyInBlockingCode);\n        }, event -> {\n            System.out.println(\"receive msg from blocking code:\" + event.result());\n            System.out.println(\"===================callback=====================\");\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                System.out.println(\"Test **WITH** TTL Agent\");\n                assertEquals(transmittedData, transmittableThreadLocal.get());\n            } else {\n                System.out.println(\"Test WITHOUT TTL Agent\");\n                assertNull(transmittableThreadLocal.get());\n            }\n            assertNull(inheritableThreadLocal.get());\n\n            System.out.println(\"===================callback=====================\");\n        });\n\n        //wait for callback\n        Thread.sleep(2000);\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/vertx4-ttl-integration/README-EN.md",
    "content": "#  Vertx 4 integration of TTL\n\n## 1. assure TTL context transmit in callback \n\n## 1.1 Decorate `io.vertx.core.Handler`\n\nUse [`TtlVertxHandler`](src/main/java/com/alibaba/ttl/integration/vertx4/TtlVertxHandler.java) to decorate `Handler`。\n\n## 1.2 Decorate `io.vertx.core.Future`\n\nAt present, `TTL` agent has decorated below `Vertx` callback components(`io.vertx.core.Future`) implementation:\n\n- `io.vertx.core.Future`\n- `io.vertx.core.impl.future.FutureImpl`\n- decoration implementation code is in [`VertxFutureTtlTransformlet.java`](src/main/java/com/alibaba/ttl/integration/vertx4/agent/transformlet/VertxFutureTtlTransformlet.java)。\n\nSample code：\n\n```java\nVertx vertx = Vertx.vertx();\n\n//build channel\nManagedChannel channel = VertxChannelBuilder\n  .forAddress(vertx, \"localhost\", 8080)\n  .usePlaintext()\n  .build();\n\n// set in parent thread\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\ncontext.set(\"value-set-in-parent\");\n\n//init stub\nio.grpc.stub.XXX stub = XXX.newVertxStub(channel);\nHelloRequest request = HelloRequest.newBuilder().setName(\"Julien\").build();\n\n//init handler\nHandler<AsyncResult<String>> handler = event -> {\n  // read in callback, value is \"value-set-in-parent\"\n  context.get();\n  if (event.succeeded()) {\n    //do something\n  } else {\n    // find exception\n  }\n};\n// extra work, create decorated TtlVertxHandler object\nTtlVertxHandler<AsyncResult<String>> ttlVertxHandler = TtlVertxHandler.get(handler);\n\n//send request\nstub.sayHello(request).onComplete(ttlVertxHandler);\n```\n## 2. assure TTL context transmit in eventbus\n\n### 2. decorate`java.lang.Runnable`\nUse [`TtlRunnable`](../../src/main/java/com/alibaba/ttl/TtlRunnable.java) to decorate`Runnable`。\n\n### 2.2 Decorate`io.netty.util.concurrent.SingleThreadEventExecutor`\n\n- decoration implementation code is in[`NettySingleThreadEventExecutorTtlTransformlet.java`](src/main/java/com/alibaba/ttl/integration/vertx4/agent/transformlet/NettySingleThreadEventExecutorTtlTransformlet.java)。\n\n"
  },
  {
    "path": "ttl-integrations/vertx4-ttl-integration/README.md",
    "content": "# Vertx 4的TTL集成\n\n## 1. 保证异步io回调中传递TTL值\n\n### 1.1修饰`io.vertx.core.Handler`\n\n使用[`TtlVertxHandler`](src/main/java/com/alibaba/ttl/integration/vertx4/TtlVertxHandler.java)来修饰传入的`Handler`。\n\n### 1.2 修饰`io.vertx.core.Future`\n\n修饰了的Vert.x执行器组件如下:\n- `io.vertx.core.Future`\n- `io.vertx.core.impl.future.FutureImpl`\n---\n- 修饰实现代码在[`VertxFutureTtlTransformlet.java`](src/main/java/com/alibaba/ttl/integration/vertx4/agent/transformlet/VertxFutureTtlTransformlet.java)。\n\n示例代码：\n\n```java\nVertx vertx = Vertx.vertx();\n\n//build channel\nManagedChannel channel = VertxChannelBuilder\n  .forAddress(vertx, \"localhost\", 8080)\n  .usePlaintext()\n  .build();\n\n// set in parent thread\nTransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();\ncontext.set(\"value-set-in-parent\");\n\n//init stub\nio.grpc.stub.XXX stub = XXX.newVertxStub(channel);\nHelloRequest request = HelloRequest.newBuilder().setName(\"Julien\").build();\n\n//init handler\nHandler<AsyncResult<String>> handler = event -> {\n  // read in callback, value is \"value-set-in-parent\"\n  context.get();\n  if (event.succeeded()) {\n    //do something\n  } else {\n    // find exception\n  }\n};\n// extra work, create decorated TtlVertxHandler object\nTtlVertxHandler<AsyncResult<String>> ttlVertxHandler = TtlVertxHandler.get(handler);\n\n//send request\nstub.sayHello(request).onComplete(ttlVertxHandler);\n```\n\n    \n## 2. 保证`eventbus`上传递TTL值\n\n### 2.1修饰`java.lang.Runnable`\n使用[`TtlRunnable`](../../src/main/java/com/alibaba/ttl/TtlRunnable.java)来修饰传入的`Runnable`。\n\n### 2.2 修饰`io.netty.util.concurrent.SingleThreadEventExecutor`\n\n修饰实现代码在[`NettySingleThreadEventExecutorTtlTransformlet.java`](src/main/java/com/alibaba/ttl/integration/vertx4/agent/transformlet/NettySingleThreadEventExecutorTtlTransformlet.java)。\n"
  },
  {
    "path": "ttl-integrations/vertx4-ttl-integration/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.ttl3</groupId>\n\t\t<artifactId>ttl3-parent</artifactId>\n\t\t<version>3.x-SNAPSHOT</version>\n\t\t<relativePath>../../pom.xml</relativePath>\n\t</parent>\n\n\t<artifactId>vertx4-ttl-integration</artifactId>\n\t<version>0.1.0-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\t<name>${project.artifactId}</name>\n\t<description>TTL integration for vert.x 4</description>\n\t<url>https://github.com/alibaba/transmittable-thread-local/tree/master/ttl-integrations/vertx4-ttl-integration</url>\n\t<inceptionYear>2021</inceptionYear>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache 2</name>\n\t\t\t<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t\t<comments>A business-friendly OSS license</comments>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<connection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</connection>\n\t\t<developerConnection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</developerConnection>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t</scm>\n\t<issueManagement>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/issues</url>\n\t\t<system>GitHub Issues</system>\n\t</issueManagement>\n\t<ciManagement>\n\t\t<system>GitHub Actions</system>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/actions</url>\n\t</ciManagement>\n\n\t<properties>\n\t\t<maven.deploy.skip>true</maven.deploy.skip>\n\n\t\t<ttl.integration.test.skip>true</ttl.integration.test.skip>\n\t\t<skipTests>${ttl.integration.test.skip}</skipTests>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>io.vertx</groupId>\n\t\t\t<artifactId>vertx-core</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.netty</groupId>\n\t\t\t<artifactId>netty-all</artifactId>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba</groupId>\n\t\t\t<artifactId>transmittable-thread-local</artifactId>\n\t\t\t<version>${project.parent.version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\n\t\t<!-- Testing frameworks and related dependencies -->\n\t\t<dependency>\n\t\t\t<groupId>io.vertx</groupId>\n\t\t\t<artifactId>vertx-web-client</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\n\t<dependencyManagement>\n\t\t<dependencies>\n\t\t\t<dependency>\n\t\t\t\t<groupId>io.netty</groupId>\n\t\t\t\t<artifactId>netty-bom</artifactId>\n\t\t\t\t<version>4.1.84.Final</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>io.vertx</groupId>\n\t\t\t\t<artifactId>vertx-stack-depchain</artifactId>\n\t\t\t\t<version>4.3.4</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<profiles>\n\t\t<profile>\n\t\t\t<id>enable-TtlAgent-forTest</id>\n\t\t\t<properties>\n\t\t\t\t<surefire.ttl.agent.log.class.transform/>\n\t\t\t\t<surefire.verbose.class/>\n\t\t\t</properties>\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<configuration>\n\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\tproperty `com.alibaba:transmittable-thread-local:jar` is generated by maven-dependency-plugin\n\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t<argLine>\n\t\t\t\t\t\t\t\t${surefire.verbose.class}\n\t\t\t\t\t\t\t\t-javaagent:${com.alibaba:transmittable-thread-local:jar}=ttl.agent.logger:STDOUT\n\t\t\t\t\t\t\t\t${surefire.ttl.agent.log.class.transform}\n\t\t\t\t\t\t\t</argLine>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\tHow to get path to dependency jar with maven\n\t\t\t\t\t\t\thttps://stackoverflow.com/a/56396097/922688\n\t\t\t\t\t\t\tApache Maven Dependency Plugin – Introduction\n\t\t\t\t\t\t\thttps://maven.apache.org/plugins/maven-dependency-plugin/\n\t\t\t\t\t\t-->\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\t<version>3.8.1</version>\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<phase>initialize</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>properties</goal>\n\t\t\t\t\t\t\t\t</goals>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>enable-LogTransform-forTest</id>\n\t\t\t<properties>\n\t\t\t\t<surefire.ttl.agent.log.class.transform>-Dttl.agent.log.class.transform</surefire.ttl.agent.log.class.transform>\n\t\t\t</properties>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>enable-verboseClass-forTest</id>\n\t\t\t<properties>\n\t\t\t\t<surefire.verbose.class>-verbose:class</surefire.verbose.class>\n\t\t\t</properties>\n\t\t</profile>\n\t</profiles>\n</project>\n"
  },
  {
    "path": "ttl-integrations/vertx4-ttl-integration/src/main/java/com/alibaba/ttl/integration/vertx4/TtlVertxHandler.java",
    "content": "package com.alibaba.ttl.integration.vertx4;\n\nimport com.alibaba.ttl.spi.TtlAttachments;\nimport com.alibaba.ttl.spi.TtlAttachmentsDelegate;\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport io.vertx.core.Handler;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.*;\n\n/**\n * {@link TtlVertxHandler} decorate {@link Handler}, so as to get {@link com.alibaba.ttl.TransmittableThreadLocal}\n * and transmit it to the time of {@link Handler} execution,\n * needed when use {@link Handler} to {@link io.vertx.core.Future}.\n * <p>\n * we will capture ttl value in another thread by modify {@link io.netty.util.concurrent.SingleThreadEventExecutor#execute(Runnable)},\n * but we can not capture the ttl value which we expect in callback of identical thread.\n * the reason of above issue is some async io callback was invoked by the\n * {@link io.netty.channel.nio.NioEventLoop#run()} rather than the {@link com.alibaba.ttl.TtlRunnable#run()}\n *\n * @author tk (305809299 at qq dot com)\n * @see io.vertx.core.Future\n * @see io.netty.channel.nio.NioEventLoop#run()\n * @see io.netty.channel.nio.NioEventLoop#processSelectedKeys()\n */\npublic class TtlVertxHandler<E> implements Handler<E>, TtlWrapper<Handler<E>>, TtlEnhanced, TtlAttachments {\n    private final AtomicReference<Object> capturedRef;\n    private final Handler<E> handler;\n    private final boolean releaseTtlValueReferenceAfterRun;\n\n    private TtlVertxHandler(@NonNull Handler<E> handler, boolean releaseTtlValueReferenceAfterRun) {\n        this.capturedRef = new AtomicReference<>(capture());\n        this.handler = handler;\n        this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;\n    }\n\n    /**\n     * wrap method {@link Handler#handle(Object)}.\n     */\n    @Override\n    public void handle(E event) {\n        final Object captured = capturedRef.get();\n        if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {\n            throw new IllegalStateException(\"TTL value reference is released after run!\");\n        }\n\n        final Object backup = replay(captured);\n        try {\n            handler.handle(event);\n        } finally {\n            restore(backup);\n        }\n    }\n\n    /**\n     * return original/unwrapped {@link Handler}.\n     */\n    @NonNull\n    public Handler<E> getHandler() {\n        return unwrap();\n    }\n\n    /**\n     * unwrap to original/unwrapped {@link Handler}.\n     *\n     * @see com.alibaba.ttl.TtlUnwrap#unwrap(Object)\n     */\n    @NonNull\n    @Override\n    public Handler<E> unwrap() {\n        return handler;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass()) {\n            return false;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        TtlVertxHandler<E> that = (TtlVertxHandler<E>) o;\n\n        return handler.equals(that.handler);\n    }\n\n    @Override\n    public int hashCode() {\n        return handler.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + handler.toString();\n    }\n\n    /**\n     * Factory method, wrap input {@link Handler} to {@link TtlVertxHandler}.\n     *\n     * @param handler input {@link Handler}. if input is {@code null}, return {@code null}.\n     * @return Wrapped {@link Handler}\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already.\n     */\n    @Nullable\n    public static <T> TtlVertxHandler<T> get(@Nullable Handler<T> handler) {\n        return get(handler, false, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link Handler} to {@link TtlVertxHandler}.\n     *\n     * @param handler                          input {@link Handler}. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlVertxHandler} is referred.\n     * @return Wrapped {@link Handler}\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already.\n     */\n    @Nullable\n    public static <T> TtlVertxHandler<T> get(@Nullable Handler<T> handler, boolean releaseTtlValueReferenceAfterRun) {\n        return get(handler, releaseTtlValueReferenceAfterRun, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link Handler} to {@link TtlVertxHandler}.\n     *\n     * @param handler                          input {@link Handler}. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlVertxHandler} is referred.\n     * @param idempotent                       is idempotent mode or not. if {@code true}, just return input {@link Handler} when it's {@link TtlVertxHandler},\n     *                                         otherwise throw {@link IllegalStateException}.\n     *                                         <B><I>Caution</I></B>: {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return Wrapped {@link Handler}\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already and not idempotent.\n     */\n    @Nullable\n    public static <T> TtlVertxHandler<T> get(@Nullable Handler<T> handler, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {\n        if (handler == null) {\n            return null;\n        }\n\n        if (handler instanceof TtlEnhanced) {\n            // avoid redundant decoration, and ensure idempotency\n            if (idempotent) {\n                return (TtlVertxHandler<T>) handler;\n            } else {\n                throw new IllegalStateException(\"Already TtlVertxHandler!\");\n            }\n        }\n        return new TtlVertxHandler<>(handler, releaseTtlValueReferenceAfterRun);\n    }\n\n    /**\n     * wrap input {@link Handler} Collection to {@link TtlVertxHandler} Collection.\n     *\n     * @param tasks task to be wrapped. if input is {@code null}, return {@code null}.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already.\n     */\n    @NonNull\n    public static <T> List<TtlVertxHandler<T>> gets(@Nullable Collection<? extends Handler<T>> tasks) {\n        return gets(tasks, false, false);\n    }\n\n    /**\n     * wrap input {@link Handler} Collection to {@link TtlVertxHandler} Collection.\n     *\n     * @param tasks                            task to be wrapped. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlVertxHandler} is referred.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already.\n     */\n    @NonNull\n    public static <T> List<TtlVertxHandler<T>> gets(@Nullable Collection<? extends Handler<T>> tasks, boolean releaseTtlValueReferenceAfterRun) {\n        return gets(tasks, releaseTtlValueReferenceAfterRun, false);\n    }\n\n    /**\n     * wrap input {@link Handler} Collection to {@link TtlVertxHandler} Collection.\n     *\n     * @param tasks                            task to be wrapped. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlVertxHandler} is referred.\n     * @param idempotent                       is idempotent mode or not. if {@code true}, just return input {@link Handler} when it's {@link TtlVertxHandler},\n     *                                         otherwise throw {@link IllegalStateException}.\n     *                                         <B><I>Caution</I></B>: {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlVertxHandler} already and not idempotent.\n     */\n    @NonNull\n    public static <T> List<TtlVertxHandler<T>> gets(@Nullable Collection<? extends Handler<T>> tasks, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {\n        if (tasks == null) {\n            return Collections.emptyList();\n        }\n\n        List<TtlVertxHandler<T>> copy = new ArrayList<>();\n        for (Handler<T> task : tasks) {\n            copy.add(TtlVertxHandler.get(task, releaseTtlValueReferenceAfterRun, idempotent));\n        }\n        return copy;\n    }\n\n    /**\n     * Unwrap {@link TtlVertxHandler} to the original/underneath one.\n     * <p>\n     * this method is {@code null}-safe, when input {@code Function} parameter is {@code null}, return {@code null};\n     * if input {@code Function} parameter is not a {@link TtlVertxHandler} just return input {@code Function}.\n     * <p>\n     * so {@code TtlVertxHandler.unwrap(TtlVertxHandler.get(function))} will always return the same input {@code function} object.\n     *\n     * @see #handle(Object)\n     * @see com.alibaba.ttl.TtlUnwrap#unwrap(Object)\n     */\n    @Nullable\n    public static <T> Handler<T> unwrap(@Nullable Handler<T> handler) {\n        if (!(handler instanceof TtlVertxHandler)) {\n            return handler;\n        } else {\n            return ((TtlVertxHandler<T>) handler).getHandler();\n        }\n    }\n\n    /**\n     * Unwrap {@link TtlVertxHandler} to the original/underneath one for collection.\n     * <p>\n     * Invoke {@link #unwrap(Handler)} for each element in input collection.\n     * <p>\n     * This method is {@code null}-safe, when input {@code Handler} parameter collection is {@code null}, return a empty list.\n     *\n     * @see #gets(Collection)\n     * @see #unwrap(Handler)\n     */\n    @NonNull\n    public static <T> List<Handler<T>> unwraps(@Nullable Collection<? extends Handler<T>> tasks) {\n        if (tasks == null) {\n            return Collections.emptyList();\n        }\n\n        List<Handler<T>> copy = new ArrayList<>();\n        for (Handler<T> task : tasks) {\n            if (!(task instanceof TtlVertxHandler)) {\n                copy.add(task);\n            } else {\n                copy.add(((TtlVertxHandler<T>) task).getHandler());\n            }\n        }\n        return copy;\n    }\n\n    private final TtlAttachmentsDelegate ttlAttachment = new TtlAttachmentsDelegate();\n\n    /**\n     * see {@link TtlAttachments#setTtlAttachment(String, Object)}\n     */\n    @Override\n    public void setTtlAttachment(@NonNull String key, Object value) {\n        ttlAttachment.setTtlAttachment(key, value);\n    }\n\n    /**\n     * see {@link TtlAttachments#getTtlAttachment(String)}\n     */\n    @Override\n    public <T> T getTtlAttachment(@NonNull String key) {\n        return ttlAttachment.getTtlAttachment(key);\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/vertx4-ttl-integration/src/main/java/com/alibaba/ttl/integration/vertx4/agent/transformlet/NettySingleThreadEventExecutorTtlTransformlet.java",
    "content": "package com.alibaba.ttl.integration.vertx4.agent.transformlet;\n\nimport com.alibaba.ttl.threadpool.agent.transformlet.helper.AbstractExecutorTtlTransformlet;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * {@link com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet}\n * for {@link io.netty.util.concurrent.SingleThreadEventExecutor}.\n *\n * @author tk (305809299 at qq dot com)\n * @see io.netty.util.concurrent.SingleThreadEventExecutor\n * @see io.vertx.core.eventbus.EventBus\n * @see io.vertx.core.impl.EventLoopContext\n * @see io.vertx.core.eventbus.Message\n */\npublic final class NettySingleThreadEventExecutorTtlTransformlet extends AbstractExecutorTtlTransformlet {\n\n    private static Set<String> getExecutorClassNames() {\n        Set<String> executorClassNames = new HashSet<>();\n\n        executorClassNames.add(\"io.netty.util.concurrent.SingleThreadEventExecutor\");\n\n        return executorClassNames;\n    }\n\n    public NettySingleThreadEventExecutorTtlTransformlet() {\n        super(getExecutorClassNames(), false);\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/vertx4-ttl-integration/src/main/java/com/alibaba/ttl/integration/vertx4/agent/transformlet/VertxFutureTtlTransformlet.java",
    "content": "package com.alibaba.ttl.integration.vertx4.agent.transformlet;\n\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.CannotCompileException;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.CtClass;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.CtMethod;\nimport com.alibaba.ttl.threadpool.agent.transformlet.javassist.NotFoundException;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport static com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.signatureOfMethod;\n\n/**\n * {@link TtlTransformlet} for {@link io.vertx.core.Future}.\n *\n * @author tk (305809299 at qq dot com)\n * @see com.alibaba.ttl.integration.vertx4.TtlVertxHandler\n * @see io.vertx.core.Future\n * @see io.vertx.core.Handler\n */\npublic class VertxFutureTtlTransformlet implements TtlTransformlet {\n    private static final Logger logger = Logger.getLogger(VertxFutureTtlTransformlet.class);\n\n    private static final String HANDLER_CLASS_NAME = \"io.vertx.core.Handler\";\n    private static final String TTL_HANDLER_CLASS_NAME = \"com.alibaba.ttl.integration.vertx4.TtlVertxHandler\";\n    private static final String FUTURE_CLASS_NAME = \"io.vertx.core.Future\";\n    private static final String FUTURE_IMPL_CLASS_NAME = \"io.vertx.core.impl.future.FutureImpl\";\n\n    private static final Set<String> TO_BE_TRANSFORMED_CLASS_NAMES = new HashSet<>();\n\n    static {\n        TO_BE_TRANSFORMED_CLASS_NAMES.add(FUTURE_CLASS_NAME);\n        TO_BE_TRANSFORMED_CLASS_NAMES.add(FUTURE_IMPL_CLASS_NAME);\n    }\n\n    @Override\n    public void doTransform(@NonNull ClassInfo classInfo) throws CannotCompileException, NotFoundException, IOException {\n        final CtClass clazz = classInfo.getCtClass();\n        if (TO_BE_TRANSFORMED_CLASS_NAMES.contains(classInfo.getClassName())) {\n            for (CtMethod method : clazz.getDeclaredMethods()) {\n                updateSetHandlerMethodsOfFutureClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(method);\n            }\n            classInfo.setModified();\n        }\n    }\n\n    private void updateSetHandlerMethodsOfFutureClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(CtMethod method) throws NotFoundException, CannotCompileException {\n        final int modifiers = method.getModifiers();\n        if (!checkMethodNeedToBeDecorated(modifiers)) {\n            return;\n        }\n\n        CtClass[] parameterTypes = method.getParameterTypes();\n        StringBuilder insertCode = new StringBuilder();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            final String paramTypeName = parameterTypes[i].getName();\n            if (HANDLER_CLASS_NAME.equals(paramTypeName)) {\n                String code = String.format(\n                    // decorate to TTL wrapper,\n                    // and then set AutoWrapper attachment/Tag\n                    \"$%d = %s.get($%1$d, false, true);\"\n                        + \"%n    com.alibaba.ttl.spi.TtlAttachmentsDelegate.setAutoWrapperAttachment($%1$d);\",\n                    i + 1, TTL_HANDLER_CLASS_NAME);\n                logger.info(\"insert code before method \" + signatureOfMethod(method) + \" of class \" + method.getDeclaringClass().getName() + \":\\n\" + code);\n                insertCode.append(code);\n            }\n        }\n        if (insertCode.length() > 0) method.insertBefore(insertCode.toString());\n    }\n\n    private boolean checkMethodNeedToBeDecorated(int modifiers) {\n        return Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && !Modifier.isAbstract(modifiers);\n    }\n}\n"
  },
  {
    "path": "ttl-integrations/vertx4-ttl-integration/src/main/resources/META-INF/ttl.agent.transformlets",
    "content": "com.alibaba.ttl.integration.vertx4.agent.transformlet.NettySingleThreadEventExecutorTtlTransformlet\ncom.alibaba.ttl.integration.vertx4.agent.transformlet.VertxFutureTtlTransformlet\n"
  },
  {
    "path": "ttl-integrations/vertx4-ttl-integration/src/test/java/com/alibaba/ttl/integration/vertx4/VertxTransformletTest.java",
    "content": "package com.alibaba.ttl.integration.vertx4;\n\nimport com.alibaba.ttl.TransmittableThreadLocal;\nimport com.alibaba.ttl.threadpool.agent.TtlAgent;\nimport io.vertx.core.Future;\nimport io.vertx.core.Vertx;\nimport io.vertx.core.buffer.Buffer;\nimport io.vertx.core.eventbus.DeliveryOptions;\nimport io.vertx.core.eventbus.Message;\nimport io.vertx.ext.web.client.HttpResponse;\nimport io.vertx.ext.web.client.WebClient;\nimport org.junit.Test;\n\nimport java.util.concurrent.TimeUnit;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\n/**\n * @author tk (soulmate.tangk at gmail dot com)\n */\npublic class VertxTransformletTest {\n    @Test\n    public void testTransmitThreadLocal_InEventbus() throws Exception {\n        final TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>();\n        final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();\n\n        final String transmittedData = \"transmitted_data\";\n        final String inheritedData = \"inherited_data_ttl\";\n        final String message = \"message_42\";\n\n        final Vertx vertx = Vertx.vertx();\n        final String address = \"consumer\";\n\n        vertx.eventBus().consumer(address, msg -> {\n            // be executed in netty event loop thread\n            System.out.println(\"========================================\");\n            assertEquals(message, msg.body());\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                System.out.println(\"Test **WITH** TTL Agent\");\n                assertEquals(transmittedData, transmittableThreadLocal.get());\n            } else {\n                System.out.println(\"Test WITHOUT TTL Agent\");\n                assertNull(transmittableThreadLocal.get());\n            }\n\n            // InheritableThreadLocal is always null\n            assertNull(inheritableThreadLocal.get());\n\n            System.out.println(\"========================================\");\n\n            //reply message can be get by {messageFuture.toCompletionStage().toCompletableFuture().get().body()} or {listener}\n            msg.reply(message);\n        });\n\n        transmittableThreadLocal.set(transmittedData);\n        inheritableThreadLocal.set(inheritedData);\n\n        // delivery message\n        final DeliveryOptions deliveryOptions = new DeliveryOptions();\n        deliveryOptions.setSendTimeout(1000);\n        final Future<Message<Object>> messageFuture = vertx.eventBus().request(address, message, deliveryOptions);\n\n        messageFuture.toCompletionStage().toCompletableFuture().get();\n        assertEquals(message, messageFuture.toCompletionStage().toCompletableFuture().get().body());\n    }\n\n    @Test\n    public void testCallback() throws Exception {\n        final TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>();\n        final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();\n        final String transmittedData = \"transmitted_data_ttl\";\n        final String inheritedData = \"inherited_data_ttl\";\n\n        final Vertx vertx = Vertx.vertx();\n        //here will bind eventLoop to client and create a new Thread for eventLoop\n        final WebClient client = WebClient.create(vertx);\n        client.get(80, \"bing.com\", \"/\")\n                .send()\n                .onSuccess(response -> {\n                    System.out.println(\"===================warmup callback=====================\");\n                    System.out.println(response.headers());\n                    System.out.println(\"===================warmup  callback=====================\");\n                })\n                .toCompletionStage().toCompletableFuture().get(10, TimeUnit.SECONDS);\n\n        //set value after eventLoop thread was created\n        transmittableThreadLocal.set(transmittedData);\n        inheritableThreadLocal.set(inheritedData);\n\n        final Future<HttpResponse<Buffer>> future = client.get(80, \"bing.com\", \"/\")\n                .send()\n                .onSuccess(response -> {\n                    System.out.println(\"===================callback=====================\");\n                    System.out.println(response.headers());\n\n                    if (TtlAgent.isTtlAgentLoaded()) {\n                        System.out.println(\"Test **WITH** TTL Agent\");\n                        assertEquals(transmittedData, transmittableThreadLocal.get());\n                    } else {\n                        System.out.println(\"Test WITHOUT TTL Agent\");\n                        assertNull(transmittableThreadLocal.get());\n                    }\n\n                    System.out.println(\"===================callback=====================\");\n                });\n\n        // block and wait to finish\n        future.toCompletionStage().toCompletableFuture().get(10, TimeUnit.SECONDS);\n    }\n}\n"
  },
  {
    "path": "ttl-kotlin/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.ttl3</groupId>\n\t\t<artifactId>ttl3-parent</artifactId>\n\t\t<version>3.x-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\n\t<artifactId>ttl-kotlin</artifactId>\n\t<packaging>jar</packaging>\n\t<name>TransmittableThreadLocal(TTL) kotlin support</name>\n\t<description>${project.name}</description>\n\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t<inceptionYear>2022</inceptionYear>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache 2</name>\n\t\t\t<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t\t<comments>A business-friendly OSS license</comments>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<connection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</connection>\n\t\t<developerConnection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</developerConnection>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t</scm>\n\t<issueManagement>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/issues</url>\n\t\t<system>GitHub Issues</system>\n\t</issueManagement>\n\t<ciManagement>\n\t\t<system>GitHub Actions</system>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/actions</url>\n\t</ciManagement>\n\t<organization>\n\t\t<name>Alibaba</name>\n\t\t<url>https://www.alibaba.com</url>\n\t</organization>\n\t<developers>\n\t\t<developer>\n\t\t\t<name>Jerry Lee</name>\n\t\t\t<id>oldratlee</id>\n\t\t\t<email>oldratlee(AT)gmail(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/oldratlee</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<name>rybalkinsd</name>\n\t\t\t<id>rybalkinsd</id>\n\t\t\t<email>yan.brikl(AT)gmail(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+3</timezone>\n\t\t\t<url>https://github.com/rybalkinsd</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t</developers>\n\n\t<properties>\n\t\t<kotlin.compiler.apiVersion>1.5</kotlin.compiler.apiVersion>\n\t</properties>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.alibaba.ttl3</groupId>\n\t\t\t<artifactId>ttl-core</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.jetbrains.kotlin</groupId>\n\t\t\t<artifactId>kotlin-stdlib-jdk8</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<!--\n\t\t\t\t\tCompile Kotlin-only source code - Using Maven - Kotlin Programming Language\n\t\t\t\t\thttps://kotlinlang.org/docs/maven.html#compile-kotlin-only-source-code\n\t\t\t\t-->\n\t\t\t\t<groupId>org.jetbrains.kotlin</groupId>\n\t\t\t\t<artifactId>kotlin-maven-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>compile</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>compile</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<sourceDirs>\n\t\t\t\t\t\t\t\t<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>\n\t\t\t\t\t\t\t</sourceDirs>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>test-compile</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>test-compile</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<sourceDirs>\n\t\t\t\t\t\t\t\t<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>\n\t\t\t\t\t\t\t</sourceDirs>\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</plugin>\n\t\t\t<plugin>\n\t\t\t\t<!--\n\t\t\t\t\thttps://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#skipMain\n\t\t\t\t\thttps://maven.apache.org/plugins/maven-compiler-plugin/testCompile-mojo.html#skip\n\t\t\t\t-->\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<skipMain>true</skipMain>\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\t<profiles>\n\t\t<profile>\n\t\t\t<id>gen-api-doc</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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<!-- use dokka-maven-plugin to generate javadoc for kotlin project -->\n\t\t\t\t\t\t<!-- see: https://kotlin.github.io/dokka/1.7.10/user_guide/maven/usage/ -->\n\t\t\t\t\t\t<groupId>org.jetbrains.dokka</groupId>\n\t\t\t\t\t\t<artifactId>dokka-maven-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<sourceDirectories>\n\t\t\t\t\t\t\t\t<directory>${project.basedir}/src/main/kotlin</directory>\n\t\t\t\t\t\t\t</sourceDirectories>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<skip>true</skip>\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": "ttl-kotlin/src/main/kotlin/com/alibaba/ttl3/kotlin/Transmitter.kt",
    "content": "package com.alibaba.ttl3.kotlin\n\nimport com.alibaba.crr.composite.Capture\nimport com.alibaba.ttl3.transmitter.Transmitter\nimport com.alibaba.ttl3.transmitter.Transmitter.*\n\n/**\n * Util method for simplifying [Transmitter.capture] and [Transmitter.restore] operations.\n *\n * @param captured captured values from other thread from [Transmitter.capture]\n * @param bizLogic biz logic\n * @param R the return type of biz logic\n * @see [Transmitter.runSupplierWithCaptured]\n * @see [Transmitter.runCallableWithCaptured]\n */\ninline fun <R> ttlRun(captured: Capture, bizLogic: () -> R): R {\n    val backup = replay(captured)\n    return try {\n        bizLogic()\n    } finally {\n        restore(backup)\n    }\n}\n\n/**\n * Util method for simplifying [Transmitter.clear] and [Transmitter.restore] operations.\n *\n * @param bizLogic biz logic\n * @param R the return type of biz logic\n * @see [Transmitter.runSupplierWithClear]\n * @see [Transmitter.runCallableWithClear]\n */\ninline fun <R> ttlRunWithClear(bizLogic: () -> R): R {\n    val backup = clear()\n    return try {\n        bizLogic()\n    } finally {\n        restore(backup)\n    }\n}\n"
  },
  {
    "path": "ttl-kotlin/src/main/kotlin/com/alibaba/ttl3/kotlin/TtlExtensions.kt",
    "content": "package com.alibaba.ttl3.kotlin\n\nimport com.alibaba.ttl3.TtlCallable\nimport com.alibaba.ttl3.TtlRunnable\nimport com.alibaba.ttl3.TtlWrappers\nimport com.alibaba.ttl3.executor.TtlExecutors\nimport com.alibaba.ttl3.spi.TtlEnhanced\nimport com.alibaba.ttl3.spi.TtlWrapper\nimport com.alibaba.ttl3.transmitter.Transmitter\nimport java.util.concurrent.*\nimport java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory\nimport java.util.function.*\nimport java.util.function.Function\n\n\n////////////////////////////////////////\n// Runnable\n////////////////////////////////////////\n\n/**\n * wrap input [Runnable] to [TtlRunnable].\n *\n * @see TtlRunnable.get\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Runnable.ttlWrap(\n    releaseTtlValueReferenceAfterRun: Boolean = false,\n    idempotent: Boolean = false\n): TtlRunnable = TtlRunnable.get(this, releaseTtlValueReferenceAfterRun, idempotent) as TtlRunnable\n\n/**\n * unwrap [TtlRunnable] to the original/underneath one.\n *\n * @see TtlRunnable.ttlUnwrap\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Runnable.ttlUnwrap(): Runnable = TtlRunnable.unwrap(this) as Runnable\n\n/**\n * wrap input [Runnable] collection to [TtlRunnable] collection.\n *\n * @see TtlRunnable.gets\n */\n@JvmName(\"ttlWrapRunnableCollection\")\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Collection<Runnable>?.ttlWrap(\n    releaseTtlValueReferenceAfterRun: Boolean = false,\n    idempotent: Boolean = false\n): List<TtlRunnable> = TtlRunnable.gets(this, releaseTtlValueReferenceAfterRun, idempotent)\n\n/**\n * wrap input nullable [Runnable] collection to [TtlRunnable] collection.\n *\n * @see TtlRunnable.gets\n */\n@JvmName(\"ttlWrapNullableRunnableCollection\")\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Collection<Runnable?>?.ttlWrap(\n    releaseTtlValueReferenceAfterRun: Boolean = false,\n    idempotent: Boolean = false\n): List<TtlRunnable?> = TtlRunnable.gets(this, releaseTtlValueReferenceAfterRun, idempotent)\n\n/**\n * unwrap [TtlRunnable] to the original/underneath one for collection.\n *\n * @see TtlRunnable.unwraps\n */\n@JvmName(\"ttlUnwrapRunnableCollection\")\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Collection<Runnable>?.ttlUnwrap(): List<Runnable> =\n    TtlRunnable.unwraps(this)\n\n/**\n * unwrap nullable [TtlRunnable] to the original/underneath one for collection.\n *\n * @see TtlRunnable.unwraps\n */\n@JvmName(\"ttlUnwrapNullableRunnableCollection\")\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Collection<Runnable?>?.ttlUnwrap(): List<Runnable?> =\n    TtlRunnable.unwraps(this)\n\n\n////////////////////////////////////////\n// Callable\n////////////////////////////////////////\n\n/**\n * wrap input [Callable] to [TtlCallable].\n *\n * @see TtlCallable.get\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <V> Callable<V>.ttlWrap(\n    releaseTtlValueReferenceAfterCall: Boolean = false,\n    idempotent: Boolean = false\n): TtlCallable<V> = TtlCallable.get(this, releaseTtlValueReferenceAfterCall, idempotent) as TtlCallable<V>\n\n/**\n * unwrap [TtlCallable] to the original/underneath one.\n *\n * @see TtlCallable.ttlUnwrap\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <V> Callable<V>.ttlUnwrap(): Callable<V> = TtlCallable.unwrap(this) as Callable<V>\n\n/**\n * wrap input [Callable] collection to [TtlCallable] collection.\n *\n * @see TtlCallable.gets\n */\n@JvmName(\"ttlWrapCallableCollection\")\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <V> Collection<Callable<V>>?.ttlWrap(\n    releaseTtlValueReferenceAfterCall: Boolean = false,\n    idempotent: Boolean = false\n): List<TtlCallable<V>> = TtlCallable.gets(this, releaseTtlValueReferenceAfterCall, idempotent)\n\n/**\n * wrap nullable input [Callable] collection to [TtlCallable] collection.\n *\n * @see TtlCallable.gets\n */\n@JvmName(\"ttlWrapNullableCallableCollection\")\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <V> Collection<Callable<V>?>?.ttlWrap(\n    releaseTtlValueReferenceAfterCall: Boolean = false,\n    idempotent: Boolean = false\n): List<TtlCallable<V>?> = TtlCallable.gets(this, releaseTtlValueReferenceAfterCall, idempotent)\n\n/**\n * unwrap [TtlCallable] to the original/underneath one for collection.\n *\n * @see TtlCallable.unwraps\n */\n@JvmName(\"ttlUnwrapCallableCollection\")\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <V> Collection<Callable<V>>?.ttlUnwrap(): List<Callable<V>> =\n    TtlCallable.unwraps(this)\n\n/**\n * unwrap nullable [TtlCallable] to the original/underneath one for collection.\n *\n * @see TtlCallable.unwraps\n */\n@JvmName(\"ttlUnwrapNullableCallableCollection\")\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <V> Collection<Callable<V>?>?.ttlUnwrap(): List<Callable<V>?> =\n    TtlCallable.unwraps(this)\n\n\n////////////////////////////////////////\n// java common functional interface\n////////////////////////////////////////\n\n/**\n * wrap [Supplier] to TTL wrapper.\n *\n * @see TtlWrappers.wrapSupplier\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <T> Supplier<T>.ttlWrap(): Supplier<T> = TtlWrappers.wrapSupplier(this) as Supplier<T>\n\n/**\n * wrap [Consumer] to TTL wrapper.\n *\n * @see TtlWrappers.wrapConsumer\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <T> Consumer<T>.ttlWrap(): Consumer<T> = TtlWrappers.wrapConsumer(this) as Consumer<T>\n\n/**\n * wrap [BiConsumer] to TTL wrapper.\n *\n * @see TtlWrappers.wrapBiConsumer\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <T, U> BiConsumer<T, U>.ttlWrap(): BiConsumer<T, U> = TtlWrappers.wrapBiConsumer(this) as BiConsumer<T, U>\n\n/**\n * wrap [Function] to TTL wrapper.\n *\n * @see TtlWrappers.wrapFunction\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <T, R> Function<T, R>.ttlWrap(): Function<T, R> =\n    TtlWrappers.wrapFunction(this) as Function<T, R>\n\n/**\n * wrap [BiFunction] to TTL wrapper.\n *\n * @see TtlWrappers.wrapFunction\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <T, U, R> BiFunction<T, U, R>.ttlWrap(): BiFunction<T, U, R> =\n    TtlWrappers.wrapBiFunction(this) as BiFunction<T, U, R>\n\n\n////////////////////////////////////////\n// kotlin function types\n////////////////////////////////////////\n\n/**\n * wrap to TTL wrapper.\n */\nfun <R> (() -> R).ttlWrap(): () -> R {\n    if (this is TtlEnhanced) return this\n\n    val captured = Transmitter.capture()\n\n    return object : () -> R, TtlWrapper<() -> R> {\n        override fun unwrap(): () -> R = this@ttlWrap\n\n        override fun invoke(): R = ttlRun(captured) { this@ttlWrap.invoke() }\n    }\n}\n\n/**\n * wrap to TTL wrapper.\n */\nfun <P1, R> ((P1) -> R).ttlWrap(): (P1) -> R {\n    if (this is TtlEnhanced) return this\n\n    val captured = Transmitter.capture()\n\n    return object : (P1) -> R, TtlWrapper<(P1) -> R> {\n        override fun unwrap(): (P1) -> R = this@ttlWrap\n\n        override fun invoke(arg: P1): R = ttlRun(captured) { this@ttlWrap.invoke(arg) }\n    }\n}\n\n/**\n * wrap to TTL wrapper.\n */\nfun <P1, P2, R> ((P1, P2) -> R).ttlWrap(): (P1, P2) -> R {\n    if (this is TtlEnhanced) return this\n\n    val captured = Transmitter.capture()\n\n    return object : (P1, P2) -> R, TtlWrapper<(P1, P2) -> R> {\n        override fun unwrap(): (P1, P2) -> R = this@ttlWrap\n\n        override fun invoke(arg1: P1, arg2: P2): R = ttlRun(captured) { this@ttlWrap.invoke(arg1, arg2) }\n    }\n}\n\n/**\n * wrap to TTL wrapper.\n */\nfun <P1, P2, P3, R> ((P1, P2, P3) -> R).ttlWrap(): (P1, P2, P3) -> R {\n    if (this is TtlEnhanced) return this\n\n    val captured = Transmitter.capture()\n\n    return object : (P1, P2, P3) -> R, TtlWrapper<(P1, P2, P3) -> R> {\n        override fun unwrap(): (P1, P2, P3) -> R = this@ttlWrap\n\n        override fun invoke(arg1: P1, arg2: P2, arg3: P3): R =\n            ttlRun(captured) { this@ttlWrap.invoke(arg1, arg2, arg3) }\n    }\n}\n\n/**\n * wrap to TTL wrapper.\n */\nfun <P1, P2, P3, P4, R> ((P1, P2, P3, P4) -> R).ttlWrap(): (P1, P2, P3, P4) -> R {\n    if (this is TtlEnhanced) return this\n\n    val captured = Transmitter.capture()\n\n    return object : (P1, P2, P3, P4) -> R, TtlWrapper<(P1, P2, P3, P4) -> R> {\n        override fun unwrap(): (P1, P2, P3, P4) -> R = this@ttlWrap\n\n        override fun invoke(arg1: P1, arg2: P2, arg3: P3, arg4: P4): R =\n            ttlRun(captured) { this@ttlWrap.invoke(arg1, arg2, arg3, arg4) }\n    }\n}\n\n\n////////////////////////////////////////\n// Generic unwrap/check method\n////////////////////////////////////////\n\n/**\n * generic unwrap method, unwrap [TtlWrapper] to the original/underneath one.\n *\n * if input parameter is not a [TtlWrapper] just return input.\n *\n * @see TtlWrappers.unwrap\n */\n@Suppress(\"UNCHECKED_CAST\", \"NOTHING_TO_INLINE\")\ninline fun <T> T.ttlUnwrap(): T = TtlWrappers.unwrap(this) as T\n\n/**\n * check the input object is a `TtlWrapper` or not.\n *\n * @see TtlWrappers.isWrapper\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <T> T.isTtlWrapper(): Boolean = TtlWrappers.isWrapper(this)\n\n\n////////////////////////////////////////\n// Executor\n////////////////////////////////////////\n\n/**\n * wrap input [Executor] to `TtlExecutor`.\n *\n * @see TtlExecutors.getTtlExecutor\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Executor.ttlWrap(): Executor =\n    TtlExecutors.getTtlExecutor(this) as Executor\n\n/**\n * wrap input [ExecutorService] to `TtlExecutorService`.\n *\n * @see TtlExecutors.getTtlExecutorService\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun ExecutorService.ttlWrap(): ExecutorService =\n    TtlExecutors.getTtlExecutorService(this) as ExecutorService\n\n/**\n * wrap input [ScheduledExecutorService] to `TtlScheduledExecutorService`.\n *\n * @see TtlExecutors.getTtlScheduledExecutorService\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun ScheduledExecutorService.ttlWrap(): ScheduledExecutorService =\n    TtlExecutors.getTtlScheduledExecutorService(this) as ScheduledExecutorService\n\n/**\n * check the executor is a TTL executor wrapper or not.\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Executor?.isTtlExecutor(): Boolean = TtlExecutors.isTtlExecutor(this)\n\n/**\n * unwrap `TtlExecutor` to the original/underneath one.\n *\n * @see TtlExecutors.unwrapTtlExecutor\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun <E : Executor> E.ttlUnwrap(): E = TtlExecutors.unwrapTtlExecutor(this) as E\n\n\n////////////////////////////////////////\n// Thread Factory\n////////////////////////////////////////\n\n/**\n * wrapper of [ThreadFactory], disable inheritable.\n *\n * @see TtlExecutors.getDisableInheritableThreadFactory\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun ThreadFactory.ttlWrapToDisableInheritableThreadFactory(): ThreadFactory =\n    TtlExecutors.getDisableInheritableThreadFactory(this) as ThreadFactory\n\n/**\n * wrapper of [Executors.defaultThreadFactory], disable inheritable.\n *\n * @see TtlExecutors.getDefaultDisableInheritableThreadFactory\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun getDefaultDisableInheritableThreadFactory(): ThreadFactory =\n    TtlExecutors.getDefaultDisableInheritableThreadFactory()\n\n/**\n * check the [ThreadFactory] is `DisableInheritableThreadFactory` or not.\n *\n * @see TtlExecutors.isDisableInheritableThreadFactory\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun ThreadFactory?.isDisableInheritableThreadFactory(): Boolean =\n    TtlExecutors.isDisableInheritableThreadFactory(this)\n\n/**\n * unwrap `DisableInheritableThreadFactory` to the original/underneath one.\n *\n * @see TtlExecutors.unwrapDisableInheritableThreadFactory\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun ThreadFactory.ttlUnwrapDisableInheritableThreadFactory(): ThreadFactory =\n    TtlExecutors.unwrapDisableInheritableThreadFactory(this) as ThreadFactory\n\n\n/**\n * wrapper of [ForkJoinWorkerThreadFactory], disable inheritable.\n *\n * @see TtlExecutors.getDisableInheritableForkJoinWorkerThreadFactory\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun ForkJoinWorkerThreadFactory.ttlWrapToDisableInheritableForkJoinWorkerThreadFactory(): ForkJoinWorkerThreadFactory =\n    TtlExecutors.getDisableInheritableForkJoinWorkerThreadFactory(this) as ForkJoinWorkerThreadFactory\n\n/**\n * wrapper of [ForkJoinPool.defaultForkJoinWorkerThreadFactory], disable inheritable.\n *\n * @see TtlExecutors.getDefaultDisableInheritableForkJoinWorkerThreadFactory\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun getDefaultDisableInheritableForkJoinWorkerThreadFactory(): ForkJoinWorkerThreadFactory =\n    TtlExecutors.getDefaultDisableInheritableForkJoinWorkerThreadFactory()\n\n/**\n * check the [ForkJoinWorkerThreadFactory] is `DisableInheritableForkJoinWorkerThreadFactory` or not.\n *\n * @see TtlExecutors.isDisableInheritableForkJoinWorkerThreadFactory\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun ForkJoinWorkerThreadFactory?.isDisableInheritableForkJoinWorkerThreadFactory(): Boolean =\n    TtlExecutors.isDisableInheritableForkJoinWorkerThreadFactory(this)\n\n/**\n * unwrap `DisableInheritableForkJoinWorkerThreadFactory` to the original/underneath one.\n *\n * @see TtlExecutors.unwrapDisableInheritableForkJoinWorkerThreadFactory\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun ForkJoinWorkerThreadFactory.ttlUnwrapDisableInheritableForkJoinWorkerThreadFactory(): ForkJoinWorkerThreadFactory =\n    TtlExecutors.unwrapDisableInheritableForkJoinWorkerThreadFactory(this) as ForkJoinWorkerThreadFactory\n\n\n////////////////////////////////////////\n// Comparator\n////////////////////////////////////////\n\n/**\n * wrapper of `Comparator<Runnable>` which unwrap [TtlRunnable] before compare,\n * aka `TtlRunnableUnwrapComparator`.\n *\n * @see TtlExecutors.getTtlRunnableUnwrapComparator\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Comparator<Runnable>.ttlWrapToTtlRunnableUnwrapComparator() =\n    TtlExecutors.getTtlRunnableUnwrapComparator(this) as Comparator<Runnable>\n\n/**\n * `TtlRunnableUnwrapComparator` that compares {@link Comparable Comparable} objects.\n *\n * @see TtlExecutors.getTtlRunnableUnwrapComparatorForComparableRunnable\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun getTtlRunnableUnwrapComparatorForComparableRunnable(): Comparator<Runnable> =\n    TtlExecutors.getTtlRunnableUnwrapComparatorForComparableRunnable()\n\n/**\n * check the `Comparator<Runnable>` is a wrapper `TtlRunnableUnwrapComparator` or not.\n *\n * @see TtlExecutors.isTtlRunnableUnwrapComparator\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Comparator<Runnable>?.isTtlRunnableUnwrapComparator(): Boolean =\n    TtlExecutors.isTtlRunnableUnwrapComparator(this)\n\n/**\n * unwrap `TtlRunnableUnwrapComparator` to the original/underneath `Comparator<Runnable>`.\n *\n * @see TtlExecutors.unwrapTtlRunnableUnwrapComparator\n */\n@Suppress(\"NOTHING_TO_INLINE\")\ninline fun Comparator<Runnable>.ttlUnwrapTtlRunnableUnwrapComparator(): Comparator<Runnable> =\n    TtlExecutors.unwrapTtlRunnableUnwrapComparator(this) as Comparator<Runnable>\n"
  },
  {
    "path": "ttl-kotlin/src/test/kotlin/com/alibaba/Utils.kt",
    "content": "package com.alibaba\n\nimport io.kotest.assertions.withClue\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport java.time.Duration\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Future\nimport java.util.concurrent.ThreadPoolExecutor\nimport java.util.concurrent.TimeUnit\n\n\n/**\n * Expand thread pool, to pre-create and cache threads.\n */\nfun expandThreadPool(executor: ExecutorService) {\n    val cpuCountX2 = Runtime.getRuntime().availableProcessors() * 2\n\n    val count = if (executor is ThreadPoolExecutor) {\n        (executor.maximumPoolSize * 2).coerceAtMost(cpuCountX2)\n    } else cpuCountX2\n\n    (0 until count).map {\n        executor.submit { Thread.sleep(10) }\n    }.forEach { it.getForTest() }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// shutdown/await util methods for test\n////////////////////////////////////////////////////////////////////////////////\n\nprivate val timeout = Duration.ofSeconds(3)\n\nfun ExecutorService.shutdownForTest() {\n    shutdown()\n    withClue(\"Fail to shutdown thread pool\") {\n        awaitTermination(timeout.toMillis(), TimeUnit.MILLISECONDS).shouldBeTrue()\n    }\n}\n\nfun <T> Future<T>.getForTest(): T = this.get(timeout.toMillis(), TimeUnit.MILLISECONDS)\n"
  },
  {
    "path": "ttl-kotlin/src/test/kotlin/com/alibaba/ttl3/kotlin/TtlExtensionsTests.kt",
    "content": "package com.alibaba.ttl3.kotlin\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.getForTest\nimport com.alibaba.shutdownForTest\nimport com.alibaba.ttl3.TransmittableThreadLocal\nimport com.alibaba.ttl3.TtlCallable\nimport com.alibaba.ttl3.TtlRunnable\nimport com.alibaba.ttl3.executor.TtlExecutors\nimport com.alibaba.ttl3.spi.TtlWrapper\nimport io.kotest.assertions.throwables.shouldThrow\nimport io.kotest.core.spec.style.FunSpec\nimport io.kotest.inspectors.forAll\nimport io.kotest.matchers.booleans.shouldBeFalse\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport io.kotest.matchers.collections.shouldBeEmpty\nimport io.kotest.matchers.collections.shouldContainInOrder\nimport io.kotest.matchers.collections.shouldHaveSize\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport io.kotest.matchers.shouldNotBe\nimport io.kotest.matchers.string.shouldContain\nimport io.kotest.matchers.types.shouldBeInstanceOf\nimport io.kotest.matchers.types.shouldBeSameInstanceAs\nimport io.kotest.matchers.types.shouldBeTypeOf\nimport io.kotest.matchers.types.shouldNotBeSameInstanceAs\nimport java.util.concurrent.*\nimport java.util.function.*\nimport kotlin.random.Random\n\nclass TtlExtensionsTests : FunSpec({\n\n    lateinit var executorService: ExecutorService\n\n    beforeSpec {\n        executorService = Executors.newFixedThreadPool(3).let {\n            expandThreadPool(it)\n            TtlExecutors.getTtlExecutorService(it)!!\n        }\n    }\n\n    afterSpec {\n        executorService.shutdownForTest()\n    }\n\n\n    test(\"ttl runnable wrap & unwrap\") {\n        val r = Runnable { }\n        r.ttlUnwrap() shouldBeSameInstanceAs r\n        r.isTtlWrapper().shouldBeFalse()\n\n\n        r.ttlWrap().let { wrap ->\n            wrap.ttlWrap(idempotent = true) shouldBeSameInstanceAs wrap\n            r.ttlWrap() shouldNotBeSameInstanceAs wrap\n            r.ttlWrap() shouldNotBe wrap\n\n            wrap.ttlUnwrap() shouldBeSameInstanceAs r\n            wrap.unwrap() shouldBeSameInstanceAs r\n            wrap.runnable shouldBeSameInstanceAs r\n            (wrap as Any).ttlUnwrap() shouldBeSameInstanceAs r\n\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeTypeOf<TtlRunnable>()\n        }\n\n        shouldThrow<IllegalStateException> {\n            r.ttlWrap().ttlWrap()\n        }.message shouldContain \"Already TtlRunnable\"\n    }\n\n    test(\"ttl runnable wraps\") {\n        val r1 = Runnable {}\n        val r2 = Runnable {}\n        val r3 = Runnable {}\n\n        val list = listOf(r1, r2, r3).ttlWrap()\n\n        list.shouldHaveSize(3)\n        list.forAll { it.shouldBeTypeOf<TtlRunnable>() }\n\n        val nullableRunnableList = listOf(r1, r2, null, r3).ttlWrap()\n        nullableRunnableList.shouldHaveSize(4)\n\n        nullableRunnableList[0].shouldBeTypeOf<TtlRunnable>()\n        nullableRunnableList[1].shouldBeTypeOf<TtlRunnable>()\n        nullableRunnableList[2].shouldBeNull()\n        nullableRunnableList[3].shouldBeTypeOf<TtlRunnable>()\n    }\n\n    test(\"ttl runnable unwraps\") {\n        val r1 = Runnable {}\n        val r2 = Runnable {}\n        val r3 = Runnable {}\n\n        listOf(null as Runnable?).ttlUnwrap().shouldContainInOrder(null)\n\n        listOf(r1).ttlUnwrap().shouldContainInOrder(r1)\n        listOf(r1.ttlWrap()).ttlUnwrap().shouldContainInOrder(r1)\n\n        listOf(r1, r2, r3).ttlUnwrap().shouldContainInOrder(r1, r2, r3)\n        listOf(r1, r2, r3).ttlWrap().ttlUnwrap().shouldContainInOrder(r1, r2, r3)\n\n        listOf(r1, r2.ttlWrap(), r3).ttlUnwrap()\n            .shouldContainInOrder(r1, r2, r3)\n        listOf(r1, r2.ttlWrap(), null, r3).ttlUnwrap()\n            .shouldContainInOrder(r1, r2, null, r3)\n\n        (null as Collection<Runnable>?).ttlUnwrap().shouldBeEmpty()\n        (null as Collection<Runnable?>?).ttlUnwrap().shouldBeEmpty()\n    }\n\n    test(\"ttl callable wrap & unwrap\") {\n        val c = Callable { 42 }\n        c.ttlUnwrap() shouldBeSameInstanceAs c\n        c.isTtlWrapper().shouldBeFalse()\n\n\n        c.ttlWrap().let { wrap ->\n            wrap.ttlWrap(idempotent = true) shouldBeSameInstanceAs wrap\n            c.ttlWrap() shouldNotBeSameInstanceAs wrap\n            c.ttlWrap() shouldNotBe wrap\n\n            wrap.ttlUnwrap() shouldBeSameInstanceAs c\n            wrap.unwrap() shouldBeSameInstanceAs c\n            wrap.callable shouldBeSameInstanceAs c\n            (wrap as Any).ttlUnwrap() shouldBeSameInstanceAs c\n\n            wrap shouldNotBeSameInstanceAs c.ttlWrap()\n            wrap shouldNotBe c.ttlWrap()\n\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeTypeOf<TtlCallable<*>>()\n        }\n\n        shouldThrow<IllegalStateException> {\n            c.ttlWrap().ttlWrap()\n        }.message shouldContain \"Already TtlCallable\"\n    }\n\n    test(\"ttl callable wraps\") {\n        val c1 = Callable { 1 }\n        val c2 = Callable { 2 }\n        val c3 = Callable { 3 }\n\n        val list = listOf(c1, c2, c3).ttlWrap()\n\n        list.shouldHaveSize(3)\n        list.forAll { it.shouldBeTypeOf<TtlCallable<*>>() }\n\n        val nullableCallableList = listOf(c1, c2, null, c3).ttlWrap()\n        nullableCallableList.shouldHaveSize(4)\n\n        nullableCallableList[0].shouldBeTypeOf<TtlCallable<*>>()\n        nullableCallableList[1].shouldBeTypeOf<TtlCallable<*>>()\n        nullableCallableList[2].shouldBeNull()\n        nullableCallableList[3].shouldBeTypeOf<TtlCallable<*>>()\n    }\n\n    test(\"ttl callable unwraps\") {\n        val c1 = Callable { 1 }\n        val c2 = Callable { 2 }\n        val c3 = Callable { 3 }\n\n        listOf(null as Callable<Int>?).shouldContainInOrder(null)\n\n        listOf(c1).ttlUnwrap().shouldContainInOrder(c1)\n        listOf(c1.ttlWrap()).ttlUnwrap().shouldContainInOrder(c1)\n\n        listOf(c1, c2, c3).ttlUnwrap().shouldContainInOrder(c1, c2, c3)\n        listOf(c1, c2, c3).ttlWrap().ttlUnwrap().shouldContainInOrder(c1, c2, c3)\n\n        listOf(c1, c2.ttlWrap(), c3).ttlUnwrap()\n            .shouldContainInOrder(c1, c2, c3)\n        listOf(c1, c2.ttlWrap(), null, c3).ttlUnwrap()\n            .shouldContainInOrder(c1, c2, null, c3)\n\n        (null as Collection<Callable<Int>>?).ttlUnwrap().shouldBeEmpty()\n        (null as Collection<Callable<Int>?>?).ttlUnwrap().shouldBeEmpty()\n    }\n\n\n    val ttl = TransmittableThreadLocal<String>()\n    val parentValue = \"parent start ${Random.nextLong()}\"\n\n    fun checkLogicInBody() {\n        ttl.get() shouldBe parentValue\n        ttl.set(\"child ${Random.nextLong()}\")\n    }\n\n    fun checkLogicAfterRun(task: Runnable) {\n        executorService.submit(task).getForTest()\n        ttl.get() shouldBe parentValue\n    }\n\n    test(\"java common functional interface\") {\n        ttl.set(parentValue)\n\n\n        val supplier = Supplier {\n            checkLogicInBody()\n            \"Hello\"\n        }\n        supplier.ttlUnwrap() shouldBeSameInstanceAs supplier\n        supplier.isTtlWrapper().shouldBeFalse()\n\n        supplier.ttlWrap().let { w ->\n            w.ttlWrap() shouldBeSameInstanceAs w\n            supplier.ttlWrap() shouldNotBeSameInstanceAs w\n            supplier.ttlWrap() shouldNotBe w\n\n            w.ttlUnwrap() shouldBeSameInstanceAs supplier\n            (w as Any).ttlUnwrap() shouldBeSameInstanceAs supplier\n\n            w.isTtlWrapper().shouldBeTrue()\n        }\n        checkLogicAfterRun {\n            supplier.get()\n        }\n\n        val consumer = Consumer<String> {\n            checkLogicInBody()\n        }\n        consumer.ttlUnwrap() shouldBeSameInstanceAs consumer\n        consumer.isTtlWrapper().shouldBeFalse()\n\n        consumer.ttlWrap().let { w ->\n            w.ttlWrap() shouldBeSameInstanceAs w\n            consumer.ttlWrap() shouldNotBeSameInstanceAs w\n            consumer.ttlWrap() shouldNotBe w\n\n            w.ttlUnwrap() shouldBeSameInstanceAs consumer\n            (w as Any).ttlUnwrap() shouldBeSameInstanceAs consumer\n\n            w.isTtlWrapper().shouldBeTrue()\n        }\n        checkLogicAfterRun {\n            consumer.accept(\"\")\n        }\n\n        val biConsumer = BiConsumer<String, String> { _, _ ->\n            checkLogicInBody()\n        }\n        biConsumer.ttlWrap().let { w ->\n            w.ttlWrap() shouldBeSameInstanceAs w\n            biConsumer.ttlWrap() shouldNotBeSameInstanceAs w\n            biConsumer.ttlWrap() shouldNotBe w\n\n            w.ttlUnwrap() shouldBeSameInstanceAs biConsumer\n            (w as Any).ttlUnwrap() shouldBeSameInstanceAs biConsumer\n\n            w.isTtlWrapper().shouldBeTrue()\n        }\n        checkLogicAfterRun {\n            biConsumer.accept(\"\", \"\")\n        }\n\n        val function = Function<String, Unit> {\n            checkLogicInBody()\n        }\n        function.ttlWrap().let { w ->\n            w.ttlWrap() shouldBeSameInstanceAs w\n            function.ttlWrap() shouldNotBeSameInstanceAs w\n            function.ttlWrap() shouldNotBe w\n\n            w.ttlUnwrap() shouldBeSameInstanceAs function\n            (w as Any).ttlUnwrap() shouldBeSameInstanceAs function\n\n            w.isTtlWrapper().shouldBeTrue()\n        }\n        checkLogicAfterRun {\n            function.apply(\"\")\n        }\n\n        val biFunction = BiFunction<String, String, Unit> { _, _ ->\n            checkLogicInBody()\n        }\n        biFunction.ttlWrap().let { w ->\n            w.ttlWrap() shouldBeSameInstanceAs w\n            biFunction.ttlWrap() shouldNotBeSameInstanceAs w\n            biFunction.ttlWrap() shouldNotBe w\n\n            w.ttlUnwrap() shouldBeSameInstanceAs biFunction\n            (w as Any).ttlUnwrap() shouldBeSameInstanceAs biFunction\n\n            w.isTtlWrapper().shouldBeTrue()\n        }\n        checkLogicAfterRun {\n            biFunction.apply(\"\", \"\")\n        }\n    }\n\n    test(\"kotlin function types\") {\n        ttl.set(parentValue)\n\n\n        val f0: () -> Unit = { checkLogicInBody() }\n        f0.ttlWrap().let { w ->\n            w.ttlWrap() shouldBeSameInstanceAs w\n            f0.ttlWrap() shouldNotBeSameInstanceAs w\n            f0.ttlWrap() shouldNotBe w\n\n            w.ttlUnwrap() shouldBeSameInstanceAs f0\n            (w as Any).ttlUnwrap() shouldBeSameInstanceAs f0\n\n            w.isTtlWrapper().shouldBeTrue()\n        }\n        checkLogicAfterRun(f0)\n\n        val f1: (String) -> Unit = { checkLogicInBody() }\n        f1.ttlWrap().let { w ->\n            w.ttlWrap() shouldBeSameInstanceAs w\n            f1.ttlWrap() shouldNotBeSameInstanceAs w\n            f1.ttlWrap() shouldNotBe w\n\n            w.ttlUnwrap() shouldBeSameInstanceAs f1\n            (w as Any).ttlUnwrap() shouldBeSameInstanceAs f1\n\n            w.isTtlWrapper().shouldBeTrue()\n        }\n        checkLogicAfterRun { f1(\"\") }\n\n        val f2: (String, Int) -> Unit = { _, _ -> checkLogicInBody() }\n        f2.ttlWrap().let { w ->\n            w.ttlWrap() shouldBeSameInstanceAs w\n            f2.ttlWrap() shouldNotBeSameInstanceAs w\n            f2.ttlWrap() shouldNotBe w\n\n            w.ttlUnwrap() shouldBeSameInstanceAs f2\n            (w as Any).ttlUnwrap() shouldBeSameInstanceAs f2\n\n            w.isTtlWrapper().shouldBeTrue()\n        }\n        checkLogicAfterRun { f2(\"\", 1) }\n\n        val f3: (String, Int, Double) -> Unit = { _, _, _ -> checkLogicInBody() }\n        f3.ttlWrap().let { w ->\n            w.ttlWrap() shouldBeSameInstanceAs w\n            f3.ttlWrap() shouldNotBeSameInstanceAs w\n            f3.ttlWrap() shouldNotBe w\n\n            w.ttlUnwrap() shouldBeSameInstanceAs f3\n            (w as Any).ttlUnwrap() shouldBeSameInstanceAs f3\n\n            w.isTtlWrapper().shouldBeTrue()\n        }\n        checkLogicAfterRun { f3(\"\", 1, 1.0) }\n\n        val f4: (String, Int, Double, Regex) -> Unit = { _, _, _, _ -> checkLogicInBody() }\n        f4.ttlWrap().let { w ->\n            w.ttlWrap() shouldBeSameInstanceAs w\n            f4.ttlWrap() shouldNotBeSameInstanceAs w\n            f4.ttlWrap() shouldNotBe w\n\n            w.ttlUnwrap() shouldBeSameInstanceAs f4\n            (w as Any).ttlUnwrap() shouldBeSameInstanceAs f4\n\n            w.isTtlWrapper().shouldBeTrue()\n        }\n        checkLogicAfterRun { f4(\"\", 1, 1.0, Regex(\".\")) }\n    }\n\n    test(\"executor wrap & unwrap\") {\n        val executor: Executor = Executors.newCachedThreadPool()\n        executor.ttlUnwrap() shouldBeSameInstanceAs executor\n        executor.isTtlExecutor().shouldBeFalse()\n        executor.isTtlWrapper().shouldBeFalse()\n\n        executor.ttlWrap().let { wrap ->\n            wrap.ttlWrap() shouldBeSameInstanceAs wrap\n            executor.ttlWrap() shouldNotBeSameInstanceAs wrap\n            executor.ttlWrap() shouldBe wrap\n\n            wrap.ttlUnwrap() shouldBeSameInstanceAs executor\n            (wrap as Any).ttlUnwrap() shouldBeSameInstanceAs executor\n\n            wrap.isTtlExecutor().shouldBeTrue()\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeInstanceOf<TtlWrapper<*>>()\n        }\n\n\n        val es: ExecutorService = Executors.newCachedThreadPool()\n        es.ttlUnwrap() shouldBeSameInstanceAs es\n        es.isTtlExecutor().shouldBeFalse()\n        es.isTtlWrapper().shouldBeFalse()\n\n        es.ttlWrap().let { wrap: ExecutorService ->\n            wrap.ttlWrap() shouldBeSameInstanceAs wrap\n            es.ttlWrap() shouldNotBeSameInstanceAs wrap\n            es.ttlWrap() shouldBe wrap\n\n            wrap.ttlUnwrap() shouldBeSameInstanceAs es\n            (wrap as Any).ttlUnwrap() shouldBeSameInstanceAs es\n\n            wrap.isTtlExecutor().shouldBeTrue()\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeInstanceOf<TtlWrapper<*>>()\n        }\n\n\n        val scheduledExecutorService: ScheduledExecutorService = ScheduledThreadPoolExecutor(1)\n        scheduledExecutorService.ttlUnwrap() shouldBeSameInstanceAs scheduledExecutorService\n        scheduledExecutorService.isTtlExecutor().shouldBeFalse()\n        scheduledExecutorService.isTtlWrapper().shouldBeFalse()\n\n        scheduledExecutorService.ttlWrap().let { wrap ->\n            wrap.ttlWrap() shouldBeSameInstanceAs wrap\n            scheduledExecutorService.ttlWrap() shouldNotBeSameInstanceAs wrap\n            scheduledExecutorService.ttlWrap() shouldBe wrap\n\n            wrap.ttlUnwrap() shouldBeSameInstanceAs scheduledExecutorService\n            (wrap as Any).ttlUnwrap() shouldBeSameInstanceAs scheduledExecutorService\n\n            wrap.isTtlExecutor().shouldBeTrue()\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeInstanceOf<TtlWrapper<*>>()\n        }\n    }\n\n    test(\"DisableInheritableThreadFactory\") {\n        val factory = Executors.defaultThreadFactory()\n        factory.ttlUnwrap() shouldBeSameInstanceAs factory\n        factory.ttlUnwrapDisableInheritableThreadFactory() shouldBeSameInstanceAs factory\n\n        factory.isDisableInheritableThreadFactory().shouldBeFalse()\n        factory.isTtlWrapper().shouldBeFalse()\n\n        factory.ttlWrapToDisableInheritableThreadFactory().let { wrap ->\n            wrap.ttlWrapToDisableInheritableThreadFactory() shouldBeSameInstanceAs wrap\n            factory.ttlWrapToDisableInheritableThreadFactory() shouldNotBeSameInstanceAs wrap\n            factory.ttlWrapToDisableInheritableThreadFactory() shouldBe wrap\n\n            wrap.ttlUnwrapDisableInheritableThreadFactory() shouldBeSameInstanceAs factory\n            wrap.ttlUnwrap() shouldBeSameInstanceAs factory\n            (wrap as Any).ttlUnwrap() shouldBeSameInstanceAs factory\n\n            wrap.isDisableInheritableThreadFactory().shouldBeTrue()\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeInstanceOf<TtlWrapper<*>>()\n        }\n\n\n        getDefaultDisableInheritableThreadFactory().let { wrap ->\n            wrap.ttlWrapToDisableInheritableThreadFactory() shouldBeSameInstanceAs wrap\n\n            wrap.ttlUnwrapDisableInheritableThreadFactory().javaClass shouldBe factory.javaClass\n            wrap.ttlUnwrap().javaClass shouldBe factory.javaClass\n            (wrap as Any).ttlUnwrap().javaClass shouldBe factory.javaClass\n\n            wrap.isDisableInheritableThreadFactory().shouldBeTrue()\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeInstanceOf<TtlWrapper<*>>()\n        }\n    }\n\n    test(\"DisableInheritableForkJoinWorkerThreadFactory\") {\n        val factory = ForkJoinPool.defaultForkJoinWorkerThreadFactory\n        factory.ttlUnwrap() shouldBeSameInstanceAs factory\n        factory.ttlUnwrapDisableInheritableForkJoinWorkerThreadFactory() shouldBeSameInstanceAs factory\n\n        factory.isDisableInheritableForkJoinWorkerThreadFactory().shouldBeFalse()\n        factory.isTtlWrapper().shouldBeFalse()\n\n        factory.ttlWrapToDisableInheritableForkJoinWorkerThreadFactory().let { wrap ->\n            wrap.ttlWrapToDisableInheritableForkJoinWorkerThreadFactory() shouldBeSameInstanceAs wrap\n            factory.ttlWrapToDisableInheritableForkJoinWorkerThreadFactory() shouldNotBeSameInstanceAs wrap\n            factory.ttlWrapToDisableInheritableForkJoinWorkerThreadFactory() shouldBe wrap\n\n            wrap.ttlUnwrapDisableInheritableForkJoinWorkerThreadFactory() shouldBeSameInstanceAs factory\n            wrap.ttlUnwrap() shouldBeSameInstanceAs factory\n            (wrap as Any).ttlUnwrap() shouldBeSameInstanceAs factory\n\n            wrap.isDisableInheritableForkJoinWorkerThreadFactory().shouldBeTrue()\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeInstanceOf<TtlWrapper<*>>()\n        }\n\n        getDefaultDisableInheritableForkJoinWorkerThreadFactory().let { wrap ->\n            wrap.ttlWrapToDisableInheritableForkJoinWorkerThreadFactory() shouldBeSameInstanceAs wrap\n\n            wrap.ttlUnwrapDisableInheritableForkJoinWorkerThreadFactory().javaClass shouldBe factory.javaClass\n            wrap.ttlUnwrap().javaClass shouldBe factory.javaClass\n            (wrap as Any).ttlUnwrap().javaClass shouldBe factory.javaClass\n\n            wrap.isDisableInheritableForkJoinWorkerThreadFactory().shouldBeTrue()\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeInstanceOf<TtlWrapper<*>>()\n        }\n    }\n\n    test(\"TtlRunnableUnwrapComparator\") {\n        val comparator: Comparator<Runnable> = Comparator.comparing { it.hashCode() }\n        comparator.ttlUnwrap() shouldBeSameInstanceAs comparator\n        comparator.ttlUnwrapTtlRunnableUnwrapComparator() shouldBeSameInstanceAs comparator\n\n        comparator.isTtlRunnableUnwrapComparator().shouldBeFalse()\n        comparator.isTtlWrapper().shouldBeFalse()\n\n        comparator.ttlWrapToTtlRunnableUnwrapComparator().let { wrap ->\n            wrap.ttlWrapToTtlRunnableUnwrapComparator() shouldBeSameInstanceAs wrap\n            comparator.ttlWrapToTtlRunnableUnwrapComparator() shouldNotBeSameInstanceAs wrap\n            comparator.ttlWrapToTtlRunnableUnwrapComparator() shouldBe wrap\n\n            wrap.ttlUnwrapTtlRunnableUnwrapComparator() shouldBeSameInstanceAs comparator\n            wrap.ttlUnwrap() shouldBeSameInstanceAs comparator\n            (wrap as Any).ttlUnwrap() shouldBeSameInstanceAs comparator\n\n            wrap.isTtlRunnableUnwrapComparator().shouldBeTrue()\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeInstanceOf<TtlWrapper<*>>()\n        }\n\n\n        getTtlRunnableUnwrapComparatorForComparableRunnable().let { wrap ->\n            wrap.ttlWrapToTtlRunnableUnwrapComparator() shouldBeSameInstanceAs wrap\n\n            wrap.ttlUnwrapTtlRunnableUnwrapComparator().javaClass.name shouldBe \"com.alibaba.ttl3.executor.ComparableComparator\"\n            wrap.ttlUnwrapTtlRunnableUnwrapComparator() shouldBeSameInstanceAs wrap.ttlUnwrapTtlRunnableUnwrapComparator()\n            wrap.ttlUnwrap() shouldBeSameInstanceAs wrap.ttlUnwrapTtlRunnableUnwrapComparator()\n            (wrap as Any).ttlUnwrap() shouldBeSameInstanceAs wrap.ttlUnwrapTtlRunnableUnwrapComparator()\n\n            wrap.isTtlRunnableUnwrapComparator().shouldBeTrue()\n            wrap.isTtlWrapper().shouldBeTrue()\n\n            wrap.shouldBeInstanceOf<TtlWrapper<*>>()\n        }\n    }\n})\n"
  },
  {
    "path": "ttl2-compatible/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.alibaba.ttl3</groupId>\n\t\t<artifactId>ttl3-parent</artifactId>\n\t\t<version>3.x-SNAPSHOT</version>\n\t\t<relativePath>../pom.xml</relativePath>\n\t</parent>\n\n\t<groupId>com.alibaba</groupId>\n\t<artifactId>transmittable-thread-local</artifactId>\n\t<packaging>jar</packaging>\n\t<name>TransmittableThreadLocal(TTL) v2 compatible</name>\n\t<description>\n\t\t📌 The missing Java™ std lib(simple &amp; 0-dependency) for framework/middleware,\n\t\tprovide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.\n\t</description>\n\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t<inceptionYear>2013</inceptionYear>\n\n\t<licenses>\n\t\t<license>\n\t\t\t<name>Apache 2</name>\n\t\t\t<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>\n\t\t\t<distribution>repo</distribution>\n\t\t\t<comments>A business-friendly OSS license</comments>\n\t\t</license>\n\t</licenses>\n\t<scm>\n\t\t<connection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</connection>\n\t\t<developerConnection>scm:git:git@github.com:alibaba/transmittable-thread-local.git</developerConnection>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local</url>\n\t</scm>\n\t<issueManagement>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/issues</url>\n\t\t<system>GitHub Issues</system>\n\t</issueManagement>\n\t<ciManagement>\n\t\t<system>GitHub Actions</system>\n\t\t<url>https://github.com/alibaba/transmittable-thread-local/actions</url>\n\t</ciManagement>\n\t<organization>\n\t\t<name>Alibaba</name>\n\t\t<url>https://www.alibaba.com</url>\n\t</organization>\n\t<developers>\n\t\t<developer>\n\t\t\t<name>Jerry Lee</name>\n\t\t\t<id>oldratlee</id>\n\t\t\t<email>oldratlee(AT)gmail(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/oldratlee</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<name>Yang Fang</name>\n\t\t\t<id>driventokill</id>\n\t\t\t<email>snoop(DOT)fy(AT)gmail(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/driventokill</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<name>wuwen</name>\n\t\t\t<id>wuwen5</id>\n\t\t\t<email>wuwen.55(AT)aliyun(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/wuwen5</url>\n\t\t\t<organization>ofpay</organization>\n\t\t\t<organizationUrl>https://www.ofpay.com</organizationUrl>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<name>David Dai</name>\n\t\t\t<id>LNAmp</id>\n\t\t\t<email>351450944(AT)qq(DOT)com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<timezone>+8</timezone>\n\t\t\t<url>https://github.com/LNAmp</url>\n\t\t\t<organization>Alibaba</organization>\n\t\t\t<organizationUrl>https://www.alibaba.com</organizationUrl>\n\t\t</developer>\n\t</developers>\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.javassist</groupId>\n\t\t\t<artifactId>javassist</artifactId>\n\t\t\t<optional>true</optional>\n\t\t</dependency>\n\n\t\t<!-- test scope dependencies -->\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-lang3</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.jetbrains.kotlinx</groupId>\n\t\t\t<artifactId>kotlinx-coroutines-core-jvm</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.reactivex.rxjava2</groupId>\n\t\t\t<artifactId>rxjava</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>io.reactivex.rxjava2</groupId>\n\t\t\t<artifactId>rxkotlin</artifactId>\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<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\tInstrumentation Specification\n\t\t\t\t\t\t\t\t\t- https://docs.oracle.com/javase/8/docs/technotes/guides/instrumentation/index.html (this doc for java 8)\n\t\t\t\t\t\t\t\t\t- https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html#package.description\n\t\t\t\t\t\t\t\tJAR Manifest - JAR File Specification\n\t\t\t\t\t\t\t\t\t- https://docs.oracle.com/en/java/javase/21/docs/specs/jar/jar.html#jar-manifest\n\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t<Premain-Class>com.alibaba.ttl.threadpool.agent.TtlAgent</Premain-Class>\n\t\t\t\t\t\t\t<Boot-Class-Path>${project.build.finalName}.jar</Boot-Class-Path>\n\t\t\t\t\t\t\t<Can-Redefine-Classes>false</Can-Redefine-Classes>\n\t\t\t\t\t\t\t<Can-Retransform-Classes>true</Can-Retransform-Classes>\n\t\t\t\t\t\t\t<Can-Set-Native-Method-Prefix>false</Can-Set-Native-Method-Prefix>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<artifactId>maven-shade-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>shade-when-package</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>shade</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<relocations>\n\t\t\t\t\t\t\t\t<relocation>\n\t\t\t\t\t\t\t\t\t<pattern>javassist</pattern>\n\t\t\t\t\t\t\t\t\t<shadedPattern>com.alibaba.ttl.threadpool.agent.transformlet.javassist</shadedPattern>\n\t\t\t\t\t\t\t\t</relocation>\n\t\t\t\t\t\t\t</relocations>\n\t\t\t\t\t\t\t<artifactSet>\n\t\t\t\t\t\t\t\t<includes>\n\t\t\t\t\t\t\t\t\t<include>org.javassist:javassist</include>\n\t\t\t\t\t\t\t\t</includes>\n\t\t\t\t\t\t\t</artifactSet>\n\t\t\t\t\t\t\t<filters>\n\t\t\t\t\t\t\t\t<filter>\n\t\t\t\t\t\t\t\t\t<artifact>org.javassist:javassist</artifact>\n\t\t\t\t\t\t\t\t\t<excludes>\n\t\t\t\t\t\t\t\t\t\t<exclude>META-INF/MANIFEST.MF</exclude>\n\t\t\t\t\t\t\t\t\t</excludes>\n\t\t\t\t\t\t\t\t</filter>\n\t\t\t\t\t\t\t</filters>\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</plugin>\n\t\t</plugins>\n\t</build>\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>config-for-jdk16+</id>\n\t\t\t<activation>\n\t\t\t\t<jdk>[16,)</jdk>\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<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludes>\n\t\t\t\t\t\t\t\t<exclude>**/*$*</exclude>\n\t\t\t\t\t\t\t\t<exclude>**/JavassistTest*</exclude>\n\t\t\t\t\t\t\t</excludes>\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>enable-ttl-agent-for-test</id>\n\t\t\t<properties>\n\t\t\t\t<!-- https://maven.apache.org/plugins/maven-jar-plugin/jar-mojo.html -->\n\t\t\t\t<ttl.built.agent.jar>\n\t\t\t\t\t${project.build.directory}/${project.artifactId}-${project.version}.jar\n\t\t\t\t</ttl.built.agent.jar>\n\t\t\t\t<ttl.agent.args>ttl.agent.logger:STDOUT</ttl.agent.args>\n\t\t\t\t<ttl.agent.extra.args/> <!-- overridden by maven -D options -->\n\t\t\t\t<ttl.agent.extra.d.options/> <!-- overridden by maven -D options -->\n\t\t\t\t<ttl.agent.jvm.arg>-javaagent:${ttl.built.agent.jar}=${ttl.agent.args},${ttl.agent.extra.args}</ttl.agent.jvm.arg>\n\t\t\t\t<ttl.agent.jvm.args>\n\t\t\t\t\t-Drun-ttl-test-under-agent=true ${ttl.agent.extra.d.options} ${ttl.agent.jvm.arg}\n\t\t\t\t</ttl.agent.jvm.args>\n\t\t\t\t<exec.mainClass>com.alibaba.demo.ttl.agent.AgentDemo</exec.mainClass> <!-- overridden by maven -D options -->\n\t\t\t</properties>\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<!--\n\t\t\t\t\t\t\treference: https://github.com/EMResearch/EvoMaster/blob/95163fb042101a71289c17f6e433f91fc1f868ef/pom.xml#L851\n\t\t\t\t\t\t-->\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<forkCount>1</forkCount>\n\t\t\t\t\t\t\t<redirectTestOutputToFile>true</redirectTestOutputToFile>\n\t\t\t\t\t\t\t<classpathDependencyExcludes>\n\t\t\t\t\t\t\t\t<classpathDependencyExclude>org.javassist:javassist</classpathDependencyExclude>\n\t\t\t\t\t\t\t\t<classpathDependencyExclude>com.github.spotbugs:spotbugs-annotations</classpathDependencyExclude>\n\t\t\t\t\t\t\t\t<classpathDependencyExclude>com.google.code.findbugs:jsr305</classpathDependencyExclude>\n\t\t\t\t\t\t\t\t<classpathDependencyExclude>org.jetbrains:annotations</classpathDependencyExclude>\n\t\t\t\t\t\t\t</classpathDependencyExcludes>\n\t\t\t\t\t\t\t<argLine>@{argLine} ${ttl.agent.jvm.args}</argLine>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\thttps://www.mojohaus.org/exec-maven-plugin/examples/example-exec-for-java-programs.html\n\t\t\t\t\t\t-->\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<configuration>\n\t\t\t\t\t\t\t<arguments>\n\t\t\t\t\t\t\t\t<argument>-Xmx1g</argument>\n\t\t\t\t\t\t\t\t<argument>-Xms256m</argument>\n\t\t\t\t\t\t\t\t<argument>-ea</argument>\n\t\t\t\t\t\t\t\t<argument>-server</argument>\n\t\t\t\t\t\t\t\t<argument>-Duser.language=en</argument>\n\t\t\t\t\t\t\t\t<argument>-Duser.country=US</argument>\n\n\t\t\t\t\t\t\t\t<argument>${ttl.agent.jvm.arg}</argument>\n\n\t\t\t\t\t\t\t\t<argument>-classpath</argument>\n\t\t\t\t\t\t\t\t<classpath/>\n\n\t\t\t\t\t\t\t\t<argument>${exec.mainClass}</argument>\n\t\t\t\t\t\t\t</arguments>\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>gen-src</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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<artifactId>maven-source-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<attach>false</attach>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<artifactId>maven-shade-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>shade-when-package</id>\n\t\t\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t\t\t<createSourcesJar>true</createSourcesJar>\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</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>gen-api-doc</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<sourceFileExcludes>\n\t\t\t\t\t\t\t\t<!-- exclude deprecated TtlEnhanced from javadoc -->\n\t\t\t\t\t\t\t\t<sourceFilesourceFileExclude>com/alibaba/ttl/TtlEnhanced.java</sourceFilesourceFileExclude>\n\t\t\t\t\t\t\t</sourceFileExcludes>\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>gen-code-cov</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<!-- https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables -->\n\t\t\t\t\t<name>env.CI</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\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.jacoco</groupId>\n\t\t\t\t\t\t<artifactId>jacoco-maven-plugin</artifactId>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludes>\n\t\t\t\t\t\t\t\t<exclude>com/alibaba/ttl/threadpool/agent/**/*.class</exclude>\n\t\t\t\t\t\t\t\t<exclude>com/alibaba/ttl/TtlTimerTask.class</exclude>\n\t\t\t\t\t\t\t</excludes>\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": "ttl2-compatible/src/main/java/com/alibaba/ttl/TransmittableThreadLocal.java",
    "content": "package com.alibaba.ttl;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport org.jetbrains.annotations.TestOnly;\n\nimport javax.annotation.ParametersAreNonnullByDefault;\nimport java.util.*;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.function.Supplier;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * {@link TransmittableThreadLocal}({@code TTL}) can transmit the value from the thread of submitting task\n * to the thread of executing task even using thread pooling components.\n * <p>\n * <b>Note</b>:<br>\n * {@link TransmittableThreadLocal} extends {@link InheritableThreadLocal},\n * so {@link TransmittableThreadLocal} first is a {@link InheritableThreadLocal}.<br>\n * If the <b>inheritable</b> ability from {@link InheritableThreadLocal} has <b>potential leaking problem</b>,\n * you can disable the <b>inheritable</b> ability:\n * <p>\n * ❶ For thread pooling components({@link java.util.concurrent.ThreadPoolExecutor},\n * {@link java.util.concurrent.ForkJoinPool}), Inheritable feature <b>should never</b> happen,\n * since threads in thread pooling components is pre-created and pooled, these threads is <b>neutral</b> to biz logic/data.\n * <br>\n * Disable inheritable for thread pooling components by wrapping thread factories using methods\n * {@link com.alibaba.ttl.threadpool.TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory) getDisableInheritableThreadFactory} /\n * {@link com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper#getDefaultDisableInheritableForkJoinWorkerThreadFactory() getDefaultDisableInheritableForkJoinWorkerThreadFactory}.\n * <br>\n * Or you can turn on \"disable inheritable for thread pool\" by {@link com.alibaba.ttl.threadpool.agent.TtlAgent}\n * to wrap thread factories for thread pooling components automatically and transparently.\n * <p>\n * ❷ In other cases, disable inheritable by overriding method {@link #childValue(Object)}.\n * <br>\n * Whether the value should be inheritable or not can be controlled by the data owner,\n * disable it <b>carefully</b> when data owner have a clear idea.\n * <pre>{@code\n * TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal<>() {\n *     protected String childValue(String parentValue) {\n *         return initialValue();\n *     }\n * }}</pre>\n * <p>\n * More discussion about \"disable the <b>inheritable</b> ability\"\n * see <a href=\"https://github.com/alibaba/transmittable-thread-local/issues/100\">\n * issue #100: disable Inheritable when it's not necessary and buggy</a>.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author Yang Fang (snoop dot fy at gmail dot com)\n * @see <a href=\"https://github.com/alibaba/transmittable-thread-local\">user guide docs and code repo of TransmittableThreadLocal(TTL)</a>\n * @see TtlRunnable\n * @see TtlCallable\n * @see com.alibaba.ttl.threadpool.TtlExecutors\n * @see com.alibaba.ttl.threadpool.TtlExecutors#getTtlExecutor(java.util.concurrent.Executor)\n * @see com.alibaba.ttl.threadpool.TtlExecutors#getTtlExecutorService(java.util.concurrent.ExecutorService)\n * @see com.alibaba.ttl.threadpool.TtlExecutors#getTtlScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)\n * @see com.alibaba.ttl.threadpool.TtlExecutors#getDefaultDisableInheritableThreadFactory()\n * @see com.alibaba.ttl.threadpool.TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)\n * @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper\n * @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper#getDefaultDisableInheritableForkJoinWorkerThreadFactory()\n * @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory)\n * @see com.alibaba.ttl.threadpool.agent.TtlAgent\n * @since 0.10.0\n */\npublic class TransmittableThreadLocal<T> extends InheritableThreadLocal<T> implements TtlCopier<T> {\n    private static final Logger logger = Logger.getLogger(TransmittableThreadLocal.class.getName());\n\n    private final boolean disableIgnoreNullValueSemantics;\n\n    /**\n     * Default constructor. Create a {@link TransmittableThreadLocal} instance with \"Ignore-Null-Value Semantics\".\n     * <p>\n     * About \"Ignore-Null-Value Semantics\":\n     *\n     * <ol>\n     *     <li>If value is {@code null}(check by {@link #get()} method), do NOT transmit this {@code ThreadLocal}.</li>\n     *     <li>If set {@code null} value, also remove value(invoke {@link #remove()} method).</li>\n     * </ol>\n     * <p>\n     * This is a pragmatic design decision:\n     * <ol>\n     * <li>use explicit value type rather than {@code null} value to express biz intent.</li>\n     * <li>safer and more robust code(avoid {@code NPE} risk).</li>\n     * </ol>\n     * <p>\n     * So it's strongly not recommended to use {@code null} value.\n     * <p>\n     * But the behavior of \"Ignore-Null-Value Semantics\" is NOT compatible with\n     * {@link ThreadLocal} and {@link InheritableThreadLocal},\n     * you can disable this behavior/semantics via using constructor {@link #TransmittableThreadLocal(boolean)}\n     * and setting parameter {@code disableIgnoreNullValueSemantics} to {@code true}.\n     * <p>\n     * More discussion about \"Ignore-Null-Value Semantics\" see\n     * <a href=\"https://github.com/alibaba/transmittable-thread-local/issues/157\">Issue #157</a>.\n     *\n     * @see #TransmittableThreadLocal(boolean)\n     */\n    public TransmittableThreadLocal() {\n        this(false);\n    }\n\n    /**\n     * Constructor, create a {@link TransmittableThreadLocal} instance\n     * with parameter {@code disableIgnoreNullValueSemantics} to control \"Ignore-Null-Value Semantics\".\n     *\n     * @param disableIgnoreNullValueSemantics disable \"Ignore-Null-Value Semantics\"\n     * @see #TransmittableThreadLocal()\n     * @since 2.11.3\n     */\n    public TransmittableThreadLocal(boolean disableIgnoreNullValueSemantics) {\n        this.disableIgnoreNullValueSemantics = disableIgnoreNullValueSemantics;\n    }\n\n    /**\n     * Creates a transmittable thread local variable.\n     * The initial value({@link #initialValue()}) of the variable is\n     * determined by invoking the {@link #get()} method on the {@code Supplier}.\n     *\n     * @param <S>      the type of the thread local's value\n     * @param supplier the supplier to be used to determine the initial value\n     * @return a new transmittable thread local variable\n     * @throws NullPointerException if the specified supplier is null\n     * @see #withInitialAndCopier(Supplier, TtlCopier)\n     * @since 2.12.2\n     */\n    @NonNull\n    @SuppressWarnings(\"ConstantConditions\")\n    public static <S> TransmittableThreadLocal<S> withInitial(@NonNull Supplier<? extends S> supplier) {\n        if (supplier == null) throw new NullPointerException(\"supplier is null\");\n\n        return new SuppliedTransmittableThreadLocal<>(supplier, null, null);\n    }\n\n    /**\n     * Creates a transmittable thread local variable.\n     * The initial value({@link #initialValue()}) of the variable is\n     * determined by invoking the {@link #get()} method on the {@code Supplier};\n     * and the child value({@link #childValue(Object)}) and the transmitting value({@link #copy(Object)}) of the variable is\n     * determined by invoking the {@link  TtlCopier#copy(Object)} method on the {@code TtlCopier}.\n     *\n     * @param <S>                        the type of the thread local's value\n     * @param supplier                   the supplier to be used to determine the initial value\n     * @param copierForChildValueAndCopy the ttl copier to be used to determine the child value and the transmitting value\n     * @return a new transmittable thread local variable\n     * @throws NullPointerException if the specified supplier or copier is null\n     * @see #withInitial(Supplier)\n     * @since 2.12.3\n     */\n    @NonNull\n    @ParametersAreNonnullByDefault\n    @SuppressWarnings(\"ConstantConditions\")\n    public static <S> TransmittableThreadLocal<S> withInitialAndCopier(Supplier<? extends S> supplier, TtlCopier<S> copierForChildValueAndCopy) {\n        if (supplier == null) throw new NullPointerException(\"supplier is null\");\n        if (copierForChildValueAndCopy == null) throw new NullPointerException(\"ttl copier is null\");\n\n        return new SuppliedTransmittableThreadLocal<>(supplier, copierForChildValueAndCopy, copierForChildValueAndCopy);\n    }\n\n    /**\n     * Creates a transmittable thread local variable.\n     * The initial value({@link #initialValue()}) of the variable is\n     * determined by invoking the {@link #get()} method on the {@code Supplier};\n     * and the child value({@link #childValue(Object)}) and the transmitting value({@link #copy(Object)}) of the variable is\n     * determined by invoking the {@link  TtlCopier#copy(Object)} method on the {@code TtlCopier}.\n     * <p>\n     * <B><I>NOTE:</I></B><br>\n     * Recommend use {@link #withInitialAndCopier(Supplier, TtlCopier)} instead of this method.\n     * In most cases, the logic of determining the child value({@link #childValue(Object)})\n     * and the transmitting value({@link #copy(Object)}) should be the same.\n     *\n     * @param <S>                 the type of the thread local's value\n     * @param supplier            the supplier to be used to determine the initial value\n     * @param copierForChildValue the ttl copier to be used to determine the child value\n     * @param copierForCopy       the ttl copier to be used to determine the transmitting value\n     * @return a new transmittable thread local variable\n     * @throws NullPointerException if the specified supplier or copier is null\n     * @see #withInitial(Supplier)\n     * @see #withInitialAndCopier(Supplier, TtlCopier)\n     * @since 2.12.3\n     */\n    @NonNull\n    @ParametersAreNonnullByDefault\n    @SuppressWarnings(\"ConstantConditions\")\n    public static <S> TransmittableThreadLocal<S> withInitialAndCopier(Supplier<? extends S> supplier, TtlCopier<S> copierForChildValue, TtlCopier<S> copierForCopy) {\n        if (supplier == null) throw new NullPointerException(\"supplier is null\");\n        if (copierForChildValue == null) throw new NullPointerException(\"ttl copier for child value is null\");\n        if (copierForCopy == null) throw new NullPointerException(\"ttl copier for copy value is null\");\n\n        return new SuppliedTransmittableThreadLocal<>(supplier, copierForChildValue, copierForCopy);\n    }\n\n    /**\n     * An extension of ThreadLocal that obtains its initial value from the specified {@code Supplier}\n     * and obtains its child value and transmitting value from the specified ttl copier.\n     */\n    private static final class SuppliedTransmittableThreadLocal<T> extends TransmittableThreadLocal<T> {\n        private final Supplier<? extends T> supplier;\n        private final TtlCopier<T> copierForChildValue;\n        private final TtlCopier<T> copierForCopy;\n\n        SuppliedTransmittableThreadLocal(Supplier<? extends T> supplier, TtlCopier<T> copierForChildValue, TtlCopier<T> copierForCopy) {\n            if (supplier == null) throw new NullPointerException(\"supplier is null\");\n            this.supplier = supplier;\n            this.copierForChildValue = copierForChildValue;\n            this.copierForCopy = copierForCopy;\n        }\n\n        @Override\n        protected T initialValue() {\n            return supplier.get();\n        }\n\n        @Override\n        protected T childValue(T parentValue) {\n            if (copierForChildValue != null) return copierForChildValue.copy(parentValue);\n            else return super.childValue(parentValue);\n        }\n\n        @Override\n        public T copy(T parentValue) {\n            if (copierForCopy != null) return copierForCopy.copy(parentValue);\n            else return super.copy(parentValue);\n        }\n    }\n\n    /**\n     * Computes the value for this transmittable thread-local variable\n     * as a function of the source thread's value at the time the task\n     * Object is created.\n     * <p>\n     * This method is called from {@link TtlRunnable} or\n     * {@link TtlCallable} when it create, before the task is started.\n     * <p>\n     * This method merely returns reference of its source thread value(the shadow copy),\n     * and should be overridden if a different behavior is desired.\n     *\n     * @since 1.0.0\n     */\n    public T copy(T parentValue) {\n        return parentValue;\n    }\n\n    /**\n     * Callback method before task object({@link TtlRunnable}/{@link TtlCallable}) execute.\n     * <p>\n     * Default behavior is to do nothing, and should be overridden\n     * if a different behavior is desired.\n     * <p>\n     * Do not throw any exception, just ignored.\n     *\n     * @since 1.2.0\n     */\n    protected void beforeExecute() {\n    }\n\n    /**\n     * Callback method after task object({@link TtlRunnable}/{@link TtlCallable}) execute.\n     * <p>\n     * Default behavior is to do nothing, and should be overridden\n     * if a different behavior is desired.\n     * <p>\n     * Do not throw any exception, just ignored.\n     *\n     * @since 1.2.0\n     */\n    protected void afterExecute() {\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public final T get() {\n        T value = super.get();\n        if (disableIgnoreNullValueSemantics || value != null) addThisToHolder();\n        return value;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public final void set(T value) {\n        if (!disableIgnoreNullValueSemantics && value == null) {\n            // may set null to remove value\n            remove();\n        } else {\n            super.set(value);\n            addThisToHolder();\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public final void remove() {\n        removeThisFromHolder();\n        super.remove();\n    }\n\n    private void superRemove() {\n        super.remove();\n    }\n\n    private T copyValue() {\n        return copy(get());\n    }\n\n    // Note about the holder:\n    // 1. holder self is a InheritableThreadLocal(a *ThreadLocal*).\n    // 2. The type of value in the holder is WeakHashMap<TransmittableThreadLocal<Object>, ?>.\n    //    2.1 but the WeakHashMap is used as a *Set*:\n    //        the value of WeakHashMap is *always* null, and never used.\n    //    2.2 WeakHashMap support *null* value.\n    private static final InheritableThreadLocal<WeakHashMap<TransmittableThreadLocal<Object>, ?>> holder =\n            new InheritableThreadLocal<WeakHashMap<TransmittableThreadLocal<Object>, ?>>() {\n                @Override\n                protected WeakHashMap<TransmittableThreadLocal<Object>, ?> initialValue() {\n                    return new WeakHashMap<>();\n                }\n\n                @Override\n                protected WeakHashMap<TransmittableThreadLocal<Object>, ?> childValue(WeakHashMap<TransmittableThreadLocal<Object>, ?> parentValue) {\n                    return new WeakHashMap<>(parentValue);\n                }\n            };\n\n    @SuppressWarnings(\"unchecked\")\n    private void addThisToHolder() {\n        if (!holder.get().containsKey(this)) {\n            holder.get().put((TransmittableThreadLocal<Object>) this, null); // WeakHashMap supports null value.\n        }\n    }\n\n    private void removeThisFromHolder() {\n        holder.get().remove(this);\n    }\n\n    private static void doExecuteCallback(boolean isBefore) {\n        // copy TTL Instances to avoid `ConcurrentModificationException`\n        // even adjust TTL instances in biz lifecycle callbacks(beforeExecute/afterExecute)\n        WeakHashMap<TransmittableThreadLocal<Object>, ?> ttlInstances = new WeakHashMap<TransmittableThreadLocal<Object>, Object>(holder.get());\n\n        for (TransmittableThreadLocal<Object> threadLocal : ttlInstances.keySet()) {\n            try {\n                if (isBefore) threadLocal.beforeExecute();\n                else threadLocal.afterExecute();\n            } catch (Throwable t) {\n                if (logger.isLoggable(Level.WARNING)) {\n                    logger.log(Level.WARNING, \"TTL exception when \" + (isBefore ? \"beforeExecute\" : \"afterExecute\") + \", cause: \" + t, t);\n                }\n            }\n        }\n    }\n\n    /**\n     * Debug only method!\n     */\n    @TestOnly\n    static void dump(@Nullable String title) {\n        if (title != null && title.length() > 0) {\n            System.out.printf(\"Start TransmittableThreadLocal[%s] Dump...%n\", title);\n        } else {\n            System.out.println(\"Start TransmittableThreadLocal Dump...\");\n        }\n\n        for (TransmittableThreadLocal<Object> threadLocal : holder.get().keySet()) {\n            System.out.println(threadLocal.get());\n        }\n        System.out.println(\"TransmittableThreadLocal Dump end!\");\n    }\n\n    /**\n     * Debug only method!\n     */\n    @TestOnly\n    static void dump() {\n        dump(null);\n    }\n\n    /**\n     * {@link Transmitter Transmitter} transmit all {@link TransmittableThreadLocal}\n     * and registered {@link ThreadLocal} values of the current thread to other thread.\n     * <p>\n     * Transmittance is completed by static methods {@link #capture()} =&gt;\n     * {@link #replay(Object)} =&gt; {@link #restore(Object)} (aka {@code CRR} operations);\n     * {@link ThreadLocal} instances are registered by method {@link Transmitter#registerThreadLocal Transmitter#registerThreadLocal}.\n     * <p>\n     * {@link Transmitter Transmitter} is <b><i>internal</i></b> manipulation api for <b><i>framework/middleware integration</i></b>;\n     * In general, you will <b><i>never</i></b> use it in the <i>biz/application codes</i>!\n     *\n     * <h2>Framework/Middleware integration to TTL transmittance</h2>\n     * Below is the example code:\n     *\n     * <pre>{@code\n     * ///////////////////////////////////////////////////////////////////////////\n     * // in thread A, capture all TransmittableThreadLocal values of thread A\n     * ///////////////////////////////////////////////////////////////////////////\n     *\n     * Object captured = Transmitter.capture(); // (1)\n     *\n     * ///////////////////////////////////////////////////////////////////////////\n     * // in thread B\n     * ///////////////////////////////////////////////////////////////////////////\n     *\n     * // replay all TransmittableThreadLocal values from thread A\n     * Object backup = Transmitter.replay(captured); // (2)\n     * try {\n     *     // your biz logic, run with the TransmittableThreadLocal values of thread B\n     *     System.out.println(\"Hello\");\n     *     // ...\n     *     return \"World\";\n     * } finally {\n     *     // restore the TransmittableThreadLocal of thread B when replay\n     *     Transmitter.restore(backup); // (3)\n     * }}</pre>\n     * <p>\n     * see the implementation code of {@link TtlRunnable} and {@link TtlCallable} for more actual code samples.\n     * <p>\n     * Of course, {@link #replay(Object)} and {@link #restore(Object)} operations can be simplified by util methods\n     * {@link #runCallableWithCaptured(Object, Callable)} or {@link #runSupplierWithCaptured(Object, Supplier)}\n     * and the adorable {@code Java 8 lambda syntax}.\n     * <p>\n     * Below is the example code:\n     *\n     * <pre>{@code\n     * ///////////////////////////////////////////////////////////////////////////\n     * // in thread A, capture all TransmittableThreadLocal values of thread A\n     * ///////////////////////////////////////////////////////////////////////////\n     *\n     * Object captured = Transmitter.capture(); // (1)\n     *\n     * ///////////////////////////////////////////////////////////////////////////\n     * // in thread B\n     * ///////////////////////////////////////////////////////////////////////////\n     *\n     * String result = runSupplierWithCaptured(captured, () -> {\n     *      // your biz logic, run with the TransmittableThreadLocal values of thread A\n     *      System.out.println(\"Hello\");\n     *      ...\n     *      return \"World\";\n     * }); // (2) + (3)}</pre>\n     * <p>\n     * The reason of providing 2 util methods is the different {@code throws Exception} type\n     * to satisfy your biz logic({@code lambda}):\n     * <ol>\n     * <li>{@link #runCallableWithCaptured(Object, Callable)}: {@code throws Exception}</li>\n     * <li>{@link #runSupplierWithCaptured(Object, Supplier)}: No {@code throws}</li>\n     * </ol>\n     * <p>\n     * If you need the different {@code throws Exception} type,\n     * you can define your own util method(function interface({@code lambda}))\n     * with your own {@code throws Exception} type.\n     *\n     * <h2>ThreadLocal Integration</h2>\n     * If you can not rewrite the existed code which use {@link ThreadLocal} to {@link TransmittableThreadLocal},\n     * register the {@link ThreadLocal} instances via the methods\n     * {@link #registerThreadLocal(ThreadLocal, TtlCopier)}/{@link #registerThreadLocalWithShadowCopier(ThreadLocal)}\n     * to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.\n     * <p>\n     * Below is the example code:\n     *\n     * <pre>{@code\n     * // the value of this ThreadLocal instance will be transmitted after registered\n     * Transmitter.registerThreadLocal(aThreadLocal, copyLambda);\n     *\n     * // Then the value of this ThreadLocal instance will not be transmitted after unregistered\n     * Transmitter.unregisterThreadLocal(aThreadLocal);}</pre>\n     * <p>\n     * The fields stored the {@code ThreadLocal} instances are generally {@code private static},\n     * so the {@code ThreadLocal} instances need be got by reflection, for example:\n     *\n     * <pre>\n     * Field field = TheClassStoredThreadLocal.class.getDeclaredField(staticFieldName);\n     * field.setAccessible(true);\n     * {@code @SuppressWarnings(\"unchecked\")}\n     * {@code ThreadLocal<T>} threadLocal = {@code (ThreadLocal<T>)} field.get(null);</pre>\n     *\n     * <B><I>Caution:</I></B><br>\n     * If the registered {@link ThreadLocal} instance is not {@link InheritableThreadLocal},\n     * the instance can NOT <B><I>{@code inherit}</I></B> value from parent thread(aka. the <b>inheritable</b> ability)!\n     *\n     * @author Yang Fang (snoop dot fy at gmail dot com)\n     * @author Jerry Lee (oldratlee at gmail dot com)\n     * @see TtlRunnable\n     * @see TtlCallable\n     * @since 2.3.0\n     */\n    public static class Transmitter {\n        /**\n         * Capture all {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values in the current thread.\n         *\n         * @return the captured {@link TransmittableThreadLocal} values\n         * @since 2.3.0\n         */\n        @NonNull\n        public static Object capture() {\n            final HashMap<Transmittee<Object, Object>, Object> transmittee2Value = new HashMap<>(transmitteeSet.size());\n            for (Transmittee<Object, Object> transmittee : transmitteeSet) {\n                try {\n                    transmittee2Value.put(transmittee, transmittee.capture());\n                } catch (Throwable t) {\n                    if (logger.isLoggable(Level.WARNING)) {\n                        logger.log(Level.WARNING, \"exception when Transmitter.capture for transmittee \" + transmittee +\n                                \"(class \" + transmittee.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                    }\n                }\n            }\n            return new Snapshot(transmittee2Value);\n        }\n\n        /**\n         * Replay the captured {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values from {@link #capture()},\n         * and return the backup {@link TransmittableThreadLocal} values in the current thread before replay.\n         *\n         * @param captured captured {@link TransmittableThreadLocal} values from other thread from {@link #capture()}\n         * @return the backup {@link TransmittableThreadLocal} values before replay\n         * @see #capture()\n         * @since 2.3.0\n         */\n        @NonNull\n        public static Object replay(@NonNull Object captured) {\n            final Snapshot capturedSnapshot = (Snapshot) captured;\n\n            final HashMap<Transmittee<Object, Object>, Object> transmittee2Value = new HashMap<>(capturedSnapshot.transmittee2Value.size());\n            for (Map.Entry<Transmittee<Object, Object>, Object> entry : capturedSnapshot.transmittee2Value.entrySet()) {\n                Transmittee<Object, Object> transmittee = entry.getKey();\n                try {\n                    Object transmitteeCaptured = entry.getValue();\n                    transmittee2Value.put(transmittee, transmittee.replay(transmitteeCaptured));\n                } catch (Throwable t) {\n                    if (logger.isLoggable(Level.WARNING)) {\n                        logger.log(Level.WARNING, \"exception when Transmitter.replay for transmittee \" + transmittee +\n                                \"(class \" + transmittee.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                    }\n                }\n            }\n            return new Snapshot(transmittee2Value);\n        }\n\n        /**\n         * Clear all {@link TransmittableThreadLocal} and registered {@link ThreadLocal} values in the current thread,\n         * and return the backup {@link TransmittableThreadLocal} values in the current thread before clear.\n         * <p>\n         * Semantically, the code {@code `Object backup = clear();`} is same as {@code `Object backup = replay(EMPTY_CAPTURE);`}.\n         * <p>\n         * The reason for providing this method is:\n         *\n         * <ol>\n         * <li>lead to more readable code</li>\n         * <li>need not provide the constant {@code EMPTY_CAPTURE}.</li>\n         * </ol>\n         *\n         * @return the backup {@link TransmittableThreadLocal} values before clear\n         * @see #replay(Object)\n         * @since 2.9.0\n         */\n        @NonNull\n        public static Object clear() {\n            final HashMap<Transmittee<Object, Object>, Object> transmittee2Value = new HashMap<>(transmitteeSet.size());\n            for (Transmittee<Object, Object> transmittee : transmitteeSet) {\n                try {\n                    transmittee2Value.put(transmittee, transmittee.clear());\n                } catch (Throwable t) {\n                    if (logger.isLoggable(Level.WARNING)) {\n                        logger.log(Level.WARNING, \"exception when Transmitter.clear for transmittee \" + transmittee +\n                                \"(class \" + transmittee.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                    }\n                }\n            }\n            return new Snapshot(transmittee2Value);\n        }\n\n        /**\n         * Restore the backup {@link TransmittableThreadLocal} and\n         * registered {@link ThreadLocal} values from {@link #replay(Object)}/{@link #clear()}.\n         *\n         * @param backup the backup {@link TransmittableThreadLocal} values from {@link #replay(Object)}/{@link #clear()}\n         * @see #replay(Object)\n         * @see #clear()\n         * @since 2.3.0\n         */\n        public static void restore(@NonNull Object backup) {\n            for (Map.Entry<Transmittee<Object, Object>, Object> entry : ((Snapshot) backup).transmittee2Value.entrySet()) {\n                Transmittee<Object, Object> transmittee = entry.getKey();\n                try {\n                    Object transmitteeBackup = entry.getValue();\n                    transmittee.restore(transmitteeBackup);\n                } catch (Throwable t) {\n                    if (logger.isLoggable(Level.WARNING)) {\n                        logger.log(Level.WARNING, \"exception when Transmitter.restore for transmittee \" + transmittee +\n                                \"(class \" + transmittee.getClass().getName() + \"), just ignored; cause: \" + t, t);\n                    }\n                }\n            }\n        }\n\n        private static class Snapshot {\n            final HashMap<Transmittee<Object, Object>, Object> transmittee2Value;\n\n            public Snapshot(HashMap<Transmittee<Object, Object>, Object> transmittee2Value) {\n                this.transmittee2Value = transmittee2Value;\n            }\n        }\n\n        /**\n         * Register the transmittee({@code CRR}), the extension point for other {@code ThreadLocal}.\n         *\n         * @param <C> the transmittee capture data type\n         * @param <B> the transmittee backup data type\n         * @return true if the input transmittee is not registered\n         * @see #unregisterTransmittee(Transmittee)\n         * @since 2.14.0\n         */\n        @SuppressWarnings(\"unchecked\")\n        public static <C, B> boolean registerTransmittee(@NonNull Transmittee<C, B> transmittee) {\n            return transmitteeSet.add((Transmittee<Object, Object>) transmittee);\n        }\n\n        /**\n         * Unregister the transmittee({@code CRR}), the extension point for other {@code ThreadLocal}.\n         *\n         * @param <C> the transmittee capture data type\n         * @param <B> the transmittee backup data type\n         * @return true if the input transmittee is registered\n         * @see #registerTransmittee(Transmittee)\n         * @since 2.14.0\n         */\n        @SuppressWarnings(\"unchecked\")\n        public static <C, B> boolean unregisterTransmittee(@NonNull Transmittee<C, B> transmittee) {\n            return transmitteeSet.remove((Transmittee<Object, Object>) transmittee);\n        }\n\n        /**\n         * The transmittee is the extension point for other {@code ThreadLocal}s\n         * which are registered by {@link #registerTransmittee(Transmittee) registerTransmittee} method.\n         * Transmittance is completed by methods {@link #capture() capture()} =&gt;\n         * {@link #replay(Object) replay(Object)} =&gt; {@link #restore(Object) restore(Object)} (aka {@code CRR} operations),\n         *\n         * @param <C> the transmittee capture data type\n         * @param <B> the transmittee backup data type\n         * @see #registerTransmittee(Transmittee)\n         * @see #unregisterTransmittee(Transmittee)\n         * @since 2.14.0\n         */\n        public interface Transmittee<C, B> {\n            /**\n             * Capture.\n             * <p>\n             * <B><I>NOTE:</I></B>\n             * <ul>\n             * <li>do NOT return {@code null}.</li>\n             * <li>do NOT throw any exceptions, just ignored.</li>\n             * </ul>\n             *\n             * @return the capture data of transmittee\n             * @since 2.14.0\n             */\n            @NonNull\n            C capture();\n\n            /**\n             * Replay.\n             * <p>\n             * <B><I>NOTE:</I></B>\n             * <ul>\n             * <li>do NOT return {@code null}.</li>\n             * <li>do NOT throw any exceptions, just ignored.</li>\n             * </ul>\n             *\n             * @param captured the capture data of transmittee, the return value of method {@link #capture()}\n             * @return the backup data of transmittee\n             * @since 2.14.0\n             */\n            @NonNull\n            B replay(@NonNull C captured);\n\n            /**\n             * Clear.\n             * <p>\n             * <B><I>NOTE:</I></B>\n             * <ul>\n             * <li>do NOT return {@code null}.</li>\n             * <li>do NOT throw any exceptions, just ignored.</li>\n             * </ul>\n             * <p>\n             * Semantically, the code {@code `B backup = clear();`} is same as {@code `B backup = replay(EMPTY_CAPTURE);`}.\n             * <p>\n             * The reason for providing this method is:\n             * <ol>\n             * <li>lead to more readable code</li>\n             * <li>need not provide the constant {@code EMPTY_CAPTURE}.</li>\n             * </ol>\n             *\n             * @return the backup data of transmittee\n             * @since 2.14.0\n             */\n            @NonNull\n            B clear();\n\n            /**\n             * Restore.\n             * <p>\n             * <B><I>NOTE:</I></B><br>\n             * do NOT throw any exceptions, just ignored.\n             *\n             * @param backup the backup data of transmittee, the return value of methods {@link #replay(Object)} or {@link #clear()}\n             * @see #replay(Object)\n             * @see #clear()\n             * @since 2.14.0\n             */\n            void restore(@NonNull B backup);\n        }\n\n        private static final Transmittee<HashMap<TransmittableThreadLocal<Object>, Object>, HashMap<TransmittableThreadLocal<Object>, Object>> ttlTransmittee =\n                new Transmittee<HashMap<TransmittableThreadLocal<Object>, Object>, HashMap<TransmittableThreadLocal<Object>, Object>>() {\n                    @NonNull\n                    @Override\n                    public HashMap<TransmittableThreadLocal<Object>, Object> capture() {\n                        final HashMap<TransmittableThreadLocal<Object>, Object> ttl2Value = new HashMap<>(holder.get().size());\n                        for (TransmittableThreadLocal<Object> threadLocal : holder.get().keySet()) {\n                            ttl2Value.put(threadLocal, threadLocal.copyValue());\n                        }\n                        return ttl2Value;\n                    }\n\n                    @NonNull\n                    @Override\n                    public HashMap<TransmittableThreadLocal<Object>, Object> replay(@NonNull HashMap<TransmittableThreadLocal<Object>, Object> captured) {\n                        final HashMap<TransmittableThreadLocal<Object>, Object> backup = new HashMap<>(holder.get().size());\n\n                        for (final Iterator<TransmittableThreadLocal<Object>> iterator = holder.get().keySet().iterator(); iterator.hasNext(); ) {\n                            TransmittableThreadLocal<Object> threadLocal = iterator.next();\n\n                            // backup\n                            backup.put(threadLocal, threadLocal.get());\n\n                            // clear the TTL values that is not in captured\n                            // avoid the extra TTL values after replay when run task\n                            if (!captured.containsKey(threadLocal)) {\n                                iterator.remove();\n                                threadLocal.superRemove();\n                            }\n                        }\n\n                        // set TTL values to captured\n                        setTtlValuesTo(captured);\n\n                        // call beforeExecute callback\n                        doExecuteCallback(true);\n\n                        return backup;\n                    }\n\n                    @NonNull\n                    @Override\n                    public HashMap<TransmittableThreadLocal<Object>, Object> clear() {\n                        return replay(new HashMap<>(0));\n                    }\n\n                    @Override\n                    public void restore(@NonNull HashMap<TransmittableThreadLocal<Object>, Object> backup) {\n                        // call afterExecute callback\n                        doExecuteCallback(false);\n\n                        for (final Iterator<TransmittableThreadLocal<Object>> iterator = holder.get().keySet().iterator(); iterator.hasNext(); ) {\n                            TransmittableThreadLocal<Object> threadLocal = iterator.next();\n\n                            // clear the TTL values that is not in backup\n                            // avoid the extra TTL values after restore\n                            if (!backup.containsKey(threadLocal)) {\n                                iterator.remove();\n                                threadLocal.superRemove();\n                            }\n                        }\n\n                        // restore TTL values\n                        setTtlValuesTo(backup);\n                    }\n                };\n\n        private static void setTtlValuesTo(@NonNull HashMap<TransmittableThreadLocal<Object>, Object> ttlValues) {\n            for (Map.Entry<TransmittableThreadLocal<Object>, Object> entry : ttlValues.entrySet()) {\n                TransmittableThreadLocal<Object> threadLocal = entry.getKey();\n                threadLocal.set(entry.getValue());\n            }\n        }\n\n        private static final Transmittee<HashMap<ThreadLocal<Object>, Object>, HashMap<ThreadLocal<Object>, Object>> threadLocalTransmittee =\n                new Transmittee<HashMap<ThreadLocal<Object>, Object>, HashMap<ThreadLocal<Object>, Object>>() {\n                    @NonNull\n                    @Override\n                    public HashMap<ThreadLocal<Object>, Object> capture() {\n                        final HashMap<ThreadLocal<Object>, Object> threadLocal2Value = new HashMap<>(threadLocalHolder.size());\n                        for (Map.Entry<ThreadLocal<Object>, TtlCopier<Object>> entry : threadLocalHolder.entrySet()) {\n                            final ThreadLocal<Object> threadLocal = entry.getKey();\n                            final TtlCopier<Object> copier = entry.getValue();\n\n                            threadLocal2Value.put(threadLocal, copier.copy(threadLocal.get()));\n                        }\n                        return threadLocal2Value;\n                    }\n\n                    @NonNull\n                    @Override\n                    public HashMap<ThreadLocal<Object>, Object> replay(@NonNull HashMap<ThreadLocal<Object>, Object> captured) {\n                        final HashMap<ThreadLocal<Object>, Object> backup = new HashMap<>(captured.size());\n\n                        for (Map.Entry<ThreadLocal<Object>, Object> entry : captured.entrySet()) {\n                            final ThreadLocal<Object> threadLocal = entry.getKey();\n                            backup.put(threadLocal, threadLocal.get());\n\n                            final Object value = entry.getValue();\n                            if (value == threadLocalClearMark) threadLocal.remove();\n                            else threadLocal.set(value);\n                        }\n\n                        return backup;\n                    }\n\n                    @NonNull\n                    @Override\n                    public HashMap<ThreadLocal<Object>, Object> clear() {\n                        final HashMap<ThreadLocal<Object>, Object> threadLocal2Value = new HashMap<>(threadLocalHolder.size());\n\n                        for (Map.Entry<ThreadLocal<Object>, TtlCopier<Object>> entry : threadLocalHolder.entrySet()) {\n                            final ThreadLocal<Object> threadLocal = entry.getKey();\n                            threadLocal2Value.put(threadLocal, threadLocalClearMark);\n                        }\n\n                        return replay(threadLocal2Value);\n                    }\n\n                    @Override\n                    public void restore(@NonNull HashMap<ThreadLocal<Object>, Object> backup) {\n                        for (Map.Entry<ThreadLocal<Object>, Object> entry : backup.entrySet()) {\n                            final ThreadLocal<Object> threadLocal = entry.getKey();\n                            threadLocal.set(entry.getValue());\n                        }\n                    }\n                };\n\n        private static final Set<Transmittee<Object, Object>> transmitteeSet = new CopyOnWriteArraySet<>();\n\n        static {\n            registerTransmittee(ttlTransmittee);\n            registerTransmittee(threadLocalTransmittee);\n        }\n\n        /**\n         * Util method for simplifying {@link #replay(Object)} and {@link #restore(Object)} operations.\n         *\n         * @param captured captured {@link TransmittableThreadLocal} values from other thread from {@link #capture()}\n         * @param bizLogic biz logic\n         * @param <R>      the return type of biz logic\n         * @return the return value of biz logic\n         * @see #capture()\n         * @see #replay(Object)\n         * @see #restore(Object)\n         * @since 2.3.1\n         */\n        public static <R> R runSupplierWithCaptured(@NonNull Object captured, @NonNull Supplier<R> bizLogic) {\n            final Object backup = replay(captured);\n            try {\n                return bizLogic.get();\n            } finally {\n                restore(backup);\n            }\n        }\n\n        /**\n         * Util method for simplifying {@link #clear()} and {@link #restore(Object)} operations.\n         *\n         * @param bizLogic biz logic\n         * @param <R>      the return type of biz logic\n         * @return the return value of biz logic\n         * @see #clear()\n         * @see #restore(Object)\n         * @since 2.9.0\n         */\n        public static <R> R runSupplierWithClear(@NonNull Supplier<R> bizLogic) {\n            final Object backup = clear();\n            try {\n                return bizLogic.get();\n            } finally {\n                restore(backup);\n            }\n        }\n\n        /**\n         * Util method for simplifying {@link #replay(Object)} and {@link #restore(Object)} operations.\n         *\n         * @param captured captured {@link TransmittableThreadLocal} values from other thread from {@link #capture()}\n         * @param bizLogic biz logic\n         * @param <R>      the return type of biz logic\n         * @return the return value of biz logic\n         * @throws Exception the exception threw by biz logic\n         * @see #capture()\n         * @see #replay(Object)\n         * @see #restore(Object)\n         * @since 2.3.1\n         */\n        @SuppressFBWarnings(\"THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION\")\n        public static <R> R runCallableWithCaptured(@NonNull Object captured, @NonNull Callable<R> bizLogic) throws Exception {\n            final Object backup = replay(captured);\n            try {\n                return bizLogic.call();\n            } finally {\n                restore(backup);\n            }\n        }\n\n        /**\n         * Util method for simplifying {@link #clear()} and {@link #restore(Object)} operations.\n         *\n         * @param bizLogic biz logic\n         * @param <R>      the return type of biz logic\n         * @return the return value of biz logic\n         * @throws Exception the exception threw by biz logic\n         * @see #clear()\n         * @see #restore(Object)\n         * @since 2.9.0\n         */\n        @SuppressFBWarnings(\"THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION\")\n        public static <R> R runCallableWithClear(@NonNull Callable<R> bizLogic) throws Exception {\n            final Object backup = clear();\n            try {\n                return bizLogic.call();\n            } finally {\n                restore(backup);\n            }\n        }\n\n        private static volatile WeakHashMap<ThreadLocal<Object>, TtlCopier<Object>> threadLocalHolder = new WeakHashMap<>();\n        private static final Object threadLocalHolderUpdateLock = new Object();\n        private static final Object threadLocalClearMark = new Object();\n\n        /**\n         * Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances\n         * to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.\n         * <p>\n         * If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}.\n         * since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability,\n         * it is unnecessary to register a {@link TransmittableThreadLocal} instance.\n         * <p>\n         * <B><I>Caution:</I></B><br>\n         * If the registered {@link ThreadLocal} instance is not {@link InheritableThreadLocal},\n         * the instance can NOT <B><I>{@code inherit}</I></B> value from parent thread(aka. the <b>inheritable</b> ability)!\n         *\n         * @param threadLocal the {@link ThreadLocal} instance that to enhance the <b>Transmittable</b> ability\n         * @param copier      the {@link TtlCopier}\n         * @return {@code true} if register the {@link ThreadLocal} instance and set {@code copier}, otherwise {@code false}\n         * @see #registerThreadLocal(ThreadLocal, TtlCopier, boolean)\n         * @since 2.11.0\n         */\n        public static <T> boolean registerThreadLocal(@NonNull ThreadLocal<T> threadLocal, @NonNull TtlCopier<T> copier) {\n            return registerThreadLocal(threadLocal, copier, false);\n        }\n\n        /**\n         * Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances\n         * to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.\n         * <p>\n         * Use the shadow copier(transmit the reference directly),\n         * and should use method {@link #registerThreadLocal(ThreadLocal, TtlCopier)} to pass a customized {@link TtlCopier} explicitly\n         * if a different behavior is desired.\n         * <p>\n         * If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}.\n         * since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability,\n         * it is unnecessary to register a {@link TransmittableThreadLocal} instance.\n         * <p>\n         * <B><I>Caution:</I></B><br>\n         * If the registered {@link ThreadLocal} instance is not {@link InheritableThreadLocal},\n         * the instance can NOT <B><I>{@code inherit}</I></B> value from parent thread(aka. the <b>inheritable</b> ability)!\n         *\n         * @param threadLocal the {@link ThreadLocal} instance that to enhance the <b>Transmittable</b> ability\n         * @return {@code true} if register the {@link ThreadLocal} instance and set {@code copier}, otherwise {@code false}\n         * @see #registerThreadLocal(ThreadLocal, TtlCopier)\n         * @see #registerThreadLocal(ThreadLocal, TtlCopier, boolean)\n         * @since 2.11.0\n         */\n        @SuppressWarnings(\"unchecked\")\n        public static <T> boolean registerThreadLocalWithShadowCopier(@NonNull ThreadLocal<T> threadLocal) {\n            return registerThreadLocal(threadLocal, (TtlCopier<T>) shadowCopier, false);\n        }\n\n        /**\n         * Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances\n         * to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.\n         * <p>\n         * If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}.\n         * since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability,\n         * it is unnecessary to register a {@link TransmittableThreadLocal} instance.\n         * <p>\n         * <B><I>Caution:</I></B><br>\n         * If the registered {@link ThreadLocal} instance is not {@link InheritableThreadLocal},\n         * the instance can NOT <B><I>{@code inherit}</I></B> value from parent thread(aka. the <b>inheritable</b> ability)!\n         *\n         * @param threadLocal the {@link ThreadLocal} instance that to enhance the <b>Transmittable</b> ability\n         * @param copier      the {@link TtlCopier}\n         * @param force       if {@code true}, update {@code copier} to {@link ThreadLocal} instance\n         *                    when a {@link ThreadLocal} instance is already registered; otherwise, ignore.\n         * @return {@code true} if register the {@link ThreadLocal} instance and set {@code copier}, otherwise {@code false}\n         * @see #registerThreadLocal(ThreadLocal, TtlCopier)\n         * @since 2.11.0\n         */\n        @SuppressWarnings(\"unchecked\")\n        public static <T> boolean registerThreadLocal(@NonNull ThreadLocal<T> threadLocal, @NonNull TtlCopier<T> copier, boolean force) {\n            if (threadLocal instanceof TransmittableThreadLocal) {\n                logger.warning(\"register a TransmittableThreadLocal instance, this is unnecessary!\");\n                return true;\n            }\n\n            synchronized (threadLocalHolderUpdateLock) {\n                if (!force && threadLocalHolder.containsKey(threadLocal)) return false;\n\n                WeakHashMap<ThreadLocal<Object>, TtlCopier<Object>> newHolder = new WeakHashMap<>(threadLocalHolder);\n                newHolder.put((ThreadLocal<Object>) threadLocal, (TtlCopier<Object>) copier);\n                threadLocalHolder = newHolder;\n                return true;\n            }\n        }\n\n        /**\n         * Register the {@link ThreadLocal}(including subclass {@link InheritableThreadLocal}) instances\n         * to enhance the <b>Transmittable</b> ability for the existed {@link ThreadLocal} instances.\n         * <p>\n         * Use the shadow copier(transmit the reference directly),\n         * and should use method {@link #registerThreadLocal(ThreadLocal, TtlCopier, boolean)} to pass a customized {@link TtlCopier} explicitly\n         * if a different behavior is desired.\n         * <p>\n         * If the registered {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}.\n         * since a {@link TransmittableThreadLocal} instance itself has the {@code Transmittable} ability,\n         * it is unnecessary to register a {@link TransmittableThreadLocal} instance.\n         * <p>\n         * <B><I>Caution:</I></B><br>\n         * If the registered {@link ThreadLocal} instance is not {@link InheritableThreadLocal},\n         * the instance can NOT <B><I>{@code inherit}</I></B> value from parent thread(aka. the <b>inheritable</b> ability)!\n         *\n         * @param threadLocal the {@link ThreadLocal} instance that to enhance the <b>Transmittable</b> ability\n         * @param force       if {@code true}, update {@code copier} to {@link ThreadLocal} instance\n         *                    when a {@link ThreadLocal} instance is already registered; otherwise, ignore.\n         * @return {@code true} if register the {@link ThreadLocal} instance and set {@code copier}, otherwise {@code false}\n         * @see #registerThreadLocal(ThreadLocal, TtlCopier)\n         * @see #registerThreadLocal(ThreadLocal, TtlCopier, boolean)\n         * @since 2.11.0\n         */\n        @SuppressWarnings(\"unchecked\")\n        public static <T> boolean registerThreadLocalWithShadowCopier(@NonNull ThreadLocal<T> threadLocal, boolean force) {\n            return registerThreadLocal(threadLocal, (TtlCopier<T>) shadowCopier, force);\n        }\n\n        /**\n         * Unregister the {@link ThreadLocal} instances\n         * to remove the <b>Transmittable</b> ability for the {@link ThreadLocal} instances.\n         * <p>\n         * If the {@link ThreadLocal} instance is {@link TransmittableThreadLocal} just ignores and return {@code true}.\n         *\n         * @see #registerThreadLocal(ThreadLocal, TtlCopier)\n         * @see #registerThreadLocalWithShadowCopier(ThreadLocal)\n         * @since 2.11.0\n         */\n        public static <T> boolean unregisterThreadLocal(@NonNull ThreadLocal<T> threadLocal) {\n            if (threadLocal instanceof TransmittableThreadLocal) {\n                logger.warning(\"unregister a TransmittableThreadLocal instance, this is unnecessary!\");\n                return true;\n            }\n\n            synchronized (threadLocalHolderUpdateLock) {\n                if (!threadLocalHolder.containsKey(threadLocal)) return false;\n\n                WeakHashMap<ThreadLocal<Object>, TtlCopier<Object>> newHolder = new WeakHashMap<>(threadLocalHolder);\n                newHolder.remove(threadLocal);\n                threadLocalHolder = newHolder;\n                return true;\n            }\n        }\n\n        private static final TtlCopier<Object> shadowCopier = parentValue -> parentValue;\n\n        @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n        private Transmitter() {\n            throw new InstantiationError(\"Must not instantiate this class\");\n        }\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/TtlCallable.java",
    "content": "package com.alibaba.ttl;\n\nimport com.alibaba.ttl.spi.TtlAttachments;\nimport com.alibaba.ttl.spi.TtlAttachmentsDelegate;\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.*;\n\n/**\n * {@link TtlCallable} decorate {@link Callable} to get {@link TransmittableThreadLocal} value\n * and transmit it to the time of {@link Callable} execution, needed when use {@link Callable} to thread pool.\n * <p>\n * Use factory method {@link #get(Callable)} to get decorated instance.\n * <p>\n * Other TTL Wrapper for common {@code Functional Interface} see {@link TtlWrappers}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.threadpool.TtlExecutors\n * @see TtlWrappers\n * @see java.util.concurrent.Executor\n * @see java.util.concurrent.ExecutorService\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ScheduledThreadPoolExecutor\n * @see java.util.concurrent.Executors\n * @see java.util.concurrent.CompletionService\n * @see java.util.concurrent.ExecutorCompletionService\n * @since 0.9.0\n */\npublic final class TtlCallable<V> implements Callable<V>, TtlWrapper<Callable<V>>, TtlEnhanced, TtlAttachments {\n    private final AtomicReference<Object> capturedRef;\n    private final Callable<V> callable;\n    private final boolean releaseTtlValueReferenceAfterCall;\n\n    private TtlCallable(@NonNull Callable<V> callable, boolean releaseTtlValueReferenceAfterCall) {\n        this.capturedRef = new AtomicReference<>(capture());\n        this.callable = callable;\n        this.releaseTtlValueReferenceAfterCall = releaseTtlValueReferenceAfterCall;\n    }\n\n    /**\n     * wrap method {@link Callable#call()}.\n     */\n    @Override\n    @SuppressFBWarnings(\"THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION\")\n    public V call() throws Exception {\n        final Object captured = capturedRef.get();\n        if (captured == null || releaseTtlValueReferenceAfterCall && !capturedRef.compareAndSet(captured, null)) {\n            throw new IllegalStateException(\"TTL value reference is released after call!\");\n        }\n\n        final Object backup = replay(captured);\n        try {\n            return callable.call();\n        } finally {\n            restore(backup);\n        }\n    }\n\n    /**\n     * return the original/underneath {@link Callable}.\n     */\n    @NonNull\n    public Callable<V> getCallable() {\n        return unwrap();\n    }\n\n    /**\n     * unwrap to the original/underneath {@link Callable}.\n     *\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.11.4\n     */\n    @NonNull\n    @Override\n    public Callable<V> unwrap() {\n        return callable;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        TtlCallable<?> that = (TtlCallable<?>) o;\n\n        return callable.equals(that.callable);\n    }\n\n    @Override\n    public int hashCode() {\n        return callable.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + callable.toString();\n    }\n\n    /**\n     * Factory method, wrap input {@link Callable} to {@link TtlCallable}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param callable input {@link Callable}\n     * @return Wrapped {@link Callable}\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T> TtlCallable<T> get(@Nullable Callable<T> callable) {\n        return get(callable, false, false);\n    }\n\n\n    /**\n     * Factory method, wrap input {@link Callable} to {@link TtlCallable}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param callable                          input {@link Callable}\n     * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @return Wrapped {@link Callable}\n     */\n    @Nullable\n    @Contract(value = \"null, _ -> null; !null, _ -> !null\", pure = true)\n    public static <T> TtlCallable<T> get(@Nullable Callable<T> callable, boolean releaseTtlValueReferenceAfterCall) {\n        return get(callable, releaseTtlValueReferenceAfterCall, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link Callable} to {@link TtlCallable}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param callable                          input {@link Callable}\n     * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @param idempotent                        is idempotent or not. {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return Wrapped {@link Callable}\n     */\n    @Nullable\n    @Contract(value = \"null, _, _ -> null; !null, _, _ -> !null\", pure = true)\n    public static <T> TtlCallable<T> get(@Nullable Callable<T> callable, boolean releaseTtlValueReferenceAfterCall, boolean idempotent) {\n        if (callable == null) return null;\n\n        if (callable instanceof TtlEnhanced) {\n            // avoid redundant decoration, and ensure idempotency\n            if (idempotent) return (TtlCallable<T>) callable;\n            else throw new IllegalStateException(\"Already TtlCallable!\");\n        }\n        return new TtlCallable<>(callable, releaseTtlValueReferenceAfterCall);\n    }\n\n    /**\n     * wrap input {@link Callable} Collection to {@link TtlCallable} Collection.\n     *\n     * @param tasks task to be wrapped\n     * @return Wrapped {@link Callable}\n     */\n    @NonNull\n    public static <T> List<TtlCallable<T>> gets(@Nullable Collection<? extends Callable<T>> tasks) {\n        return gets(tasks, false, false);\n    }\n\n    /**\n     * wrap input {@link Callable} Collection to {@link TtlCallable} Collection.\n     *\n     * @param tasks                             task to be wrapped\n     * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @return Wrapped {@link Callable}\n     */\n    @NonNull\n    public static <T> List<TtlCallable<T>> gets(@Nullable Collection<? extends Callable<T>> tasks, boolean releaseTtlValueReferenceAfterCall) {\n        return gets(tasks, releaseTtlValueReferenceAfterCall, false);\n    }\n\n    /**\n     * wrap input {@link Callable} Collection to {@link TtlCallable} Collection.\n     *\n     * @param tasks                             task to be wrapped\n     * @param releaseTtlValueReferenceAfterCall release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @param idempotent                        is idempotent or not. {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return Wrapped {@link Callable}\n     */\n    @NonNull\n    public static <T> List<TtlCallable<T>> gets(@Nullable Collection<? extends Callable<T>> tasks, boolean releaseTtlValueReferenceAfterCall, boolean idempotent) {\n        if (tasks == null) return Collections.emptyList();\n\n        List<TtlCallable<T>> copy = new ArrayList<>();\n        for (Callable<T> task : tasks) {\n            copy.add(TtlCallable.get(task, releaseTtlValueReferenceAfterCall, idempotent));\n        }\n        return copy;\n    }\n\n    /**\n     * Unwrap {@link TtlCallable} to the original/underneath one.\n     * <p>\n     * this method is {@code null}-safe, when input {@code Callable} parameter is {@code null}, return {@code null};\n     * if input {@code Callable} parameter is not a {@link TtlCallable} just return input {@code Callable}.\n     * <p>\n     * so {@code TtlCallable.unwrap(TtlCallable.get(callable))} will always return the same input {@code callable} object.\n     *\n     * @see #get(Callable)\n     * @see com.alibaba.ttl.TtlUnwrap#unwrap(Object)\n     * @since 2.10.2\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T> Callable<T> unwrap(@Nullable Callable<T> callable) {\n        if (!(callable instanceof TtlCallable)) return callable;\n        else return ((TtlCallable<T>) callable).getCallable();\n    }\n\n    /**\n     * Unwrap {@link TtlCallable} to the original/underneath one.\n     * <p>\n     * Invoke {@link #unwrap(Callable)} for each element in input collection.\n     * <p>\n     * This method is {@code null}-safe, when input {@code Callable} collection parameter is {@code null}, return an empty list.\n     *\n     * @see #gets(Collection)\n     * @see #unwrap(Callable)\n     * @since 2.10.2\n     */\n    @NonNull\n    public static <T> List<Callable<T>> unwraps(@Nullable Collection<? extends Callable<T>> tasks) {\n        if (tasks == null) return Collections.emptyList();\n\n        List<Callable<T>> copy = new ArrayList<>();\n        for (Callable<T> task : tasks) {\n            if (!(task instanceof TtlCallable)) copy.add(task);\n            else copy.add(((TtlCallable<T>) task).getCallable());\n        }\n        return copy;\n    }\n\n    private final TtlAttachmentsDelegate ttlAttachment = new TtlAttachmentsDelegate();\n\n    /**\n     * see {@link TtlAttachments#setTtlAttachment(String, Object)}\n     *\n     * @since 2.11.0\n     */\n    @Override\n    public void setTtlAttachment(@NonNull String key, Object value) {\n        ttlAttachment.setTtlAttachment(key, value);\n    }\n\n    /**\n     * see {@link TtlAttachments#getTtlAttachment(String)}\n     *\n     * @since 2.11.0\n     */\n    @Override\n    public <T> T getTtlAttachment(@NonNull String key) {\n        return ttlAttachment.getTtlAttachment(key);\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/TtlCopier.java",
    "content": "package com.alibaba.ttl;\n\n/**\n * {@code TtlCopier} copies the value when {@link TransmittableThreadLocal.Transmitter#capture() Transmitter#capture()},\n * use the copied value when {@link TransmittableThreadLocal.Transmitter#replay(Object) Transmitter#replay(Object)}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see TransmittableThreadLocal.Transmitter\n * @see TransmittableThreadLocal.Transmitter#capture()\n * @since 2.11.0\n */\n@FunctionalInterface\npublic interface TtlCopier<T> {\n    /**\n     * Computes the value for {@link TransmittableThreadLocal}\n     * or registered {@link ThreadLocal}(registered by method {@link TransmittableThreadLocal.Transmitter#registerThreadLocal Transmitter#registerThreadLocal})\n     * as a function of the source thread's value at the time the task\n     * Object is created.\n     * <p>\n     * This method is called from {@link TtlRunnable} or\n     * {@link TtlCallable} when it create, before the task is started\n     * (aka. called when {@link TransmittableThreadLocal.Transmitter#capture() Transmitter#capture()}).\n     *\n     * @see TransmittableThreadLocal.Transmitter#registerThreadLocal(ThreadLocal, TtlCopier)\n     * @see TransmittableThreadLocal.Transmitter#registerThreadLocalWithShadowCopier(ThreadLocal)\n     * @see TransmittableThreadLocal.Transmitter#unregisterThreadLocal\n     */\n    T copy(T parentValue);\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/TtlEnhanced.java",
    "content": "package com.alibaba.ttl;\n\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\n/**\n * @see com.alibaba.ttl.spi.TtlAttachments\n * @deprecated Use {@link com.alibaba.ttl.spi.TtlEnhanced} instead.\n */\n@Deprecated\n@SuppressFBWarnings({\"NM_SAME_SIMPLE_NAME_AS_INTERFACE\"})\n//   [ERROR] The class name com.alibaba.ttl.TtlEnhanced shadows\n//   the simple name of implemented interface com.alibaba.ttl.spi.TtlEnhanced [com.alibaba.ttl.TtlEnhanced]\npublic interface TtlEnhanced extends com.alibaba.ttl.spi.TtlEnhanced {\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/TtlRecursiveAction.java",
    "content": "package com.alibaba.ttl;\n\nimport com.alibaba.ttl.spi.TtlEnhanced;\n\nimport java.util.concurrent.ForkJoinTask;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.*;\n\n/**\n * A recursive resultless {@link ForkJoinTask} enhanced by {@link TransmittableThreadLocal}.\n * <p>\n * Recommend to use {@link com.alibaba.ttl.threadpool.agent.TtlAgent};\n * Specially for {@code Java 8} {@link java.util.stream.Stream} and {@link java.util.concurrent.CompletableFuture},\n * these async task are executed by {@link java.util.concurrent.ForkJoinPool} via {@link ForkJoinTask} at the bottom.\n *\n * @author LNAmp\n * @see java.util.concurrent.RecursiveAction\n * @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper\n * @see com.alibaba.ttl.threadpool.agent.TtlAgent\n * @since 2.4.0\n */\npublic abstract class TtlRecursiveAction extends ForkJoinTask<Void> implements TtlEnhanced {\n\n    private static final long serialVersionUID = -5753568484583412377L;\n\n    private final Object captured = capture();\n\n    protected TtlRecursiveAction() {\n    }\n\n    /**\n     * The main computation performed by this task.\n     */\n    protected abstract void compute();\n\n    /**\n     * see {@link ForkJoinTask#getRawResult()}\n     */\n    public final Void getRawResult() {\n        return null;\n    }\n\n    /**\n     * see {@link ForkJoinTask#setRawResult(Object)}\n     */\n    protected final void setRawResult(Void mustBeNull) {\n    }\n\n    /**\n     * Implements execution conventions for RecursiveActions.\n     */\n    protected final boolean exec() {\n        final Object backup = replay(captured);\n        try {\n            compute();\n            return true;\n        } finally {\n            restore(backup);\n        }\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/TtlRecursiveTask.java",
    "content": "package com.alibaba.ttl;\n\nimport com.alibaba.ttl.spi.TtlEnhanced;\n\nimport java.util.concurrent.ForkJoinTask;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.*;\n\n/**\n * A recursive result-bearing {@link ForkJoinTask} enhanced by {@link TransmittableThreadLocal}.\n * <p>\n * Recommend to use {@link com.alibaba.ttl.threadpool.agent.TtlAgent};\n * Specially for {@code Java 8} {@link java.util.stream.Stream} and {@link java.util.concurrent.CompletableFuture},\n * these async task are executed by {@link java.util.concurrent.ForkJoinPool} via {@link ForkJoinTask} at the bottom.\n *\n * @author LNAmp\n * @see java.util.concurrent.RecursiveTask\n * @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper\n * @see com.alibaba.ttl.threadpool.agent.TtlAgent\n * @since 2.4.0\n */\npublic abstract class TtlRecursiveTask<V> extends ForkJoinTask<V> implements TtlEnhanced {\n\n    private static final long serialVersionUID = 1814679366926362436L;\n\n    private final Object captured = capture();\n\n    protected TtlRecursiveTask() {\n    }\n\n    /**\n     * The result of the computation.\n     */\n    V result;\n\n    /**\n     * The main computation performed by this task.\n     *\n     * @return the result of the computation\n     */\n    protected abstract V compute();\n\n    /**\n     * see {@link ForkJoinTask#getRawResult()}\n     */\n    public final V getRawResult() {\n        return result;\n    }\n\n    /**\n     * see {@link ForkJoinTask#setRawResult(Object)}\n     */\n    protected final void setRawResult(V value) {\n        result = value;\n    }\n\n    /**\n     * Implements execution conventions for RecursiveTask.\n     */\n    protected final boolean exec() {\n        final Object backup = replay(captured);\n        try {\n            result = compute();\n            return true;\n        } finally {\n            restore(backup);\n        }\n    }\n\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/TtlRunnable.java",
    "content": "package com.alibaba.ttl;\n\nimport com.alibaba.ttl.spi.TtlAttachments;\nimport com.alibaba.ttl.spi.TtlAttachmentsDelegate;\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.*;\n\n/**\n * {@link TtlRunnable} decorate {@link Runnable} to get {@link TransmittableThreadLocal} value\n * and transmit it to the time of {@link Runnable} execution, needed when use {@link Runnable} to thread pool.\n * <p>\n * Use factory methods {@link #get} / {@link #gets} to create instance.\n * <p>\n * Other TTL Wrapper for common {@code Functional Interface} see {@link TtlWrappers}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.threadpool.TtlExecutors\n * @see TtlWrappers\n * @see java.util.concurrent.Executor\n * @see java.util.concurrent.ExecutorService\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ScheduledThreadPoolExecutor\n * @see java.util.concurrent.Executors\n * @since 0.9.0\n */\npublic final class TtlRunnable implements Runnable, TtlWrapper<Runnable>, TtlEnhanced, TtlAttachments {\n    private final AtomicReference<Object> capturedRef;\n    private final Runnable runnable;\n    private final boolean releaseTtlValueReferenceAfterRun;\n\n    private TtlRunnable(@NonNull Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {\n        this.capturedRef = new AtomicReference<>(capture());\n        this.runnable = runnable;\n        this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;\n    }\n\n    /**\n     * wrap method {@link Runnable#run()}.\n     */\n    @Override\n    public void run() {\n        final Object captured = capturedRef.get();\n        if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {\n            throw new IllegalStateException(\"TTL value reference is released after run!\");\n        }\n\n        final Object backup = replay(captured);\n        try {\n            runnable.run();\n        } finally {\n            restore(backup);\n        }\n    }\n\n    /**\n     * return original/unwrapped {@link Runnable}.\n     */\n    @NonNull\n    public Runnable getRunnable() {\n        return unwrap();\n    }\n\n    /**\n     * unwrap to original/unwrapped {@link Runnable}.\n     *\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.11.4\n     */\n    @NonNull\n    @Override\n    public Runnable unwrap() {\n        return runnable;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        TtlRunnable that = (TtlRunnable) o;\n\n        return runnable.equals(that.runnable);\n    }\n\n    @Override\n    public int hashCode() {\n        return runnable.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + runnable.toString();\n    }\n\n    /**\n     * Factory method, wrap input {@link Runnable} to {@link TtlRunnable}.\n     *\n     * @param runnable input {@link Runnable}. if input is {@code null}, return {@code null}.\n     * @return Wrapped {@link Runnable}\n     * @throws IllegalStateException when input is {@link TtlRunnable} already.\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static TtlRunnable get(@Nullable Runnable runnable) {\n        return get(runnable, false, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link Runnable} to {@link TtlRunnable}.\n     *\n     * @param runnable                         input {@link Runnable}. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @return Wrapped {@link Runnable}\n     * @throws IllegalStateException when input is {@link TtlRunnable} already.\n     */\n    @Nullable\n    @Contract(value = \"null, _ -> null; !null, _ -> !null\", pure = true)\n    public static TtlRunnable get(@Nullable Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {\n        return get(runnable, releaseTtlValueReferenceAfterRun, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link Runnable} to {@link TtlRunnable}.\n     *\n     * @param runnable                         input {@link Runnable}. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @param idempotent                       is idempotent mode or not. if {@code true}, just return input {@link Runnable} when it's {@link TtlRunnable},\n     *                                         otherwise throw {@link IllegalStateException}.\n     *                                         <B><I>Caution</I></B>: {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return Wrapped {@link Runnable}\n     * @throws IllegalStateException when input is {@link TtlRunnable} already and not idempotent.\n     */\n    @Nullable\n    @Contract(value = \"null, _, _ -> null; !null, _, _ -> !null\", pure = true)\n    public static TtlRunnable get(@Nullable Runnable runnable, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {\n        if (runnable == null) return null;\n\n        if (runnable instanceof TtlEnhanced) {\n            // avoid redundant decoration, and ensure idempotency\n            if (idempotent) return (TtlRunnable) runnable;\n            else throw new IllegalStateException(\"Already TtlRunnable!\");\n        }\n        return new TtlRunnable(runnable, releaseTtlValueReferenceAfterRun);\n    }\n\n    /**\n     * wrap input {@link Runnable} Collection to {@link TtlRunnable} Collection.\n     *\n     * @param tasks task to be wrapped. if input is {@code null}, return {@code null}.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlRunnable} already.\n     */\n    @NonNull\n    public static List<TtlRunnable> gets(@Nullable Collection<? extends Runnable> tasks) {\n        return gets(tasks, false, false);\n    }\n\n    /**\n     * wrap input {@link Runnable} Collection to {@link TtlRunnable} Collection.\n     *\n     * @param tasks                            task to be wrapped. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlRunnable} already.\n     */\n    @NonNull\n    public static List<TtlRunnable> gets(@Nullable Collection<? extends Runnable> tasks, boolean releaseTtlValueReferenceAfterRun) {\n        return gets(tasks, releaseTtlValueReferenceAfterRun, false);\n    }\n\n    /**\n     * wrap input {@link Runnable} Collection to {@link TtlRunnable} Collection.\n     *\n     * @param tasks                            task to be wrapped. if input is {@code null}, return {@code null}.\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlRunnable} is referred.\n     * @param idempotent                       is idempotent mode or not. if {@code true}, just return input {@link Runnable} when it's {@link TtlRunnable},\n     *                                         otherwise throw {@link IllegalStateException}.\n     *                                         <B><I>Caution</I></B>: {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return wrapped tasks\n     * @throws IllegalStateException when input is {@link TtlRunnable} already and not idempotent.\n     */\n    @NonNull\n    public static List<TtlRunnable> gets(@Nullable Collection<? extends Runnable> tasks, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {\n        if (tasks == null) return Collections.emptyList();\n\n        List<TtlRunnable> copy = new ArrayList<>();\n        for (Runnable task : tasks) {\n            copy.add(TtlRunnable.get(task, releaseTtlValueReferenceAfterRun, idempotent));\n        }\n        return copy;\n    }\n\n    /**\n     * Unwrap {@link TtlRunnable} to the original/underneath one.\n     * <p>\n     * this method is {@code null}-safe, when input {@code Runnable} parameter is {@code null}, return {@code null};\n     * if input {@code Runnable} parameter is not a {@link TtlRunnable} just return input {@code Runnable}.\n     * <p>\n     * so {@code TtlRunnable.unwrap(TtlRunnable.get(runnable))} will always return the same input {@code runnable} object.\n     *\n     * @see #get(Runnable)\n     * @see com.alibaba.ttl.TtlUnwrap#unwrap(Object)\n     * @since 2.10.2\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static Runnable unwrap(@Nullable Runnable runnable) {\n        if (!(runnable instanceof TtlRunnable)) return runnable;\n        else return ((TtlRunnable) runnable).getRunnable();\n    }\n\n    /**\n     * Unwrap {@link TtlRunnable} to the original/underneath one for collection.\n     * <p>\n     * Invoke {@link #unwrap(Runnable)} for each element in input collection.\n     * <p>\n     * This method is {@code null}-safe, when input {@code Runnable} parameter collection is {@code null}, return a empty list.\n     *\n     * @see #gets(Collection)\n     * @see #unwrap(Runnable)\n     * @since 2.10.2\n     */\n    @NonNull\n    public static List<Runnable> unwraps(@Nullable Collection<? extends Runnable> tasks) {\n        if (tasks == null) return Collections.emptyList();\n\n        List<Runnable> copy = new ArrayList<>();\n        for (Runnable task : tasks) {\n            if (!(task instanceof TtlRunnable)) copy.add(task);\n            else copy.add(((TtlRunnable) task).getRunnable());\n        }\n        return copy;\n    }\n\n    private final TtlAttachmentsDelegate ttlAttachment = new TtlAttachmentsDelegate();\n\n    /**\n     * see {@link TtlAttachments#setTtlAttachment(String, Object)}\n     *\n     * @since 2.11.0\n     */\n    @Override\n    public void setTtlAttachment(@NonNull String key, Object value) {\n        ttlAttachment.setTtlAttachment(key, value);\n    }\n\n    /**\n     * see {@link TtlAttachments#getTtlAttachment(String)}\n     *\n     * @since 2.11.0\n     */\n    @Override\n    public <T> T getTtlAttachment(@NonNull String key) {\n        return ttlAttachment.getTtlAttachment(key);\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/TtlTimerTask.java",
    "content": "package com.alibaba.ttl;\n\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.*;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.*;\n\n/**\n * {@link TtlTimerTask} decorate {@link TimerTask} to get {@link TransmittableThreadLocal} value\n * and transmit it to the time of {@link TtlTimerTask} execution, needed when use {@link TtlTimerTask} to {@link java.util.TimerTask}.\n * <p>\n * Use factory method {@link #get(TimerTask)} to create instance.\n * <p>\n * <b>NOTE:</b>\n * The {@link TtlTimerTask} make the method {@link TimerTask#scheduledExecutionTime()} in\n * the origin {@link TimerTask} lose effectiveness! Use {@link com.alibaba.ttl.threadpool.agent.TtlAgent} instead.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see java.util.Timer\n * @see TimerTask\n * @see <a href=\"https://alibaba.github.io/Alibaba-Java-Coding-Guidelines/#concurrency\">Alibaba Java Coding Guidelines - Concurrency - Item 10: [Mandatory] Run multiple TimeTask by using ScheduledExecutorService rather than Timer because Timer will kill all running threads in case of failing to catch exceptions.</a>\n * @see com.alibaba.ttl.threadpool.agent.TtlAgent\n * @since 0.9.1\n * @deprecated Use {@link TtlRunnable}, {@link java.util.concurrent.ScheduledExecutorService} instead of {@link java.util.Timer}, {@link java.util.TimerTask}.\n */\n@Deprecated\npublic final class TtlTimerTask extends TimerTask implements TtlWrapper<TimerTask>, TtlEnhanced {\n    private final AtomicReference<Object> capturedRef;\n    private final TimerTask timerTask;\n    private final boolean releaseTtlValueReferenceAfterRun;\n\n    private TtlTimerTask(@NonNull TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun) {\n        this.capturedRef = new AtomicReference<>(capture());\n        this.timerTask = timerTask;\n        this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;\n    }\n\n    /**\n     * wrap method {@link TimerTask#run()}.\n     */\n    @Override\n    public void run() {\n        final Object captured = capturedRef.get();\n        if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {\n            throw new IllegalStateException(\"TTL value reference is released after run!\");\n        }\n\n        final Object backup = replay(captured);\n        try {\n            timerTask.run();\n        } finally {\n            restore(backup);\n        }\n    }\n\n    @Override\n    public boolean cancel() {\n        timerTask.cancel();\n        return super.cancel();\n    }\n\n    /**\n     * return original/unwrapped {@link TimerTask}.\n     */\n    @NonNull\n    public TimerTask getTimerTask() {\n        return unwrap();\n    }\n\n    /**\n     * unwrap to original/unwrapped {@link TimerTask}.\n     *\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.11.4\n     */\n    @NonNull\n    @Override\n    public TimerTask unwrap() {\n        return timerTask;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        TtlTimerTask that = (TtlTimerTask) o;\n\n        return timerTask.equals(that.timerTask);\n    }\n\n    @Override\n    public int hashCode() {\n        return timerTask != null ? timerTask.hashCode() : 0;\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + timerTask.toString();\n    }\n\n    /**\n     * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param timerTask input {@link TimerTask}\n     * @return Wrapped {@link TimerTask}\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static TtlTimerTask get(@Nullable TimerTask timerTask) {\n        return get(timerTask, false, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param timerTask                        input {@link TimerTask}\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlTimerTask} is referred.\n     * @return Wrapped {@link TimerTask}\n     */\n    @Nullable\n    @Contract(value = \"null, _ -> null; !null, _ -> !null\", pure = true)\n    public static TtlTimerTask get(@Nullable TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun) {\n        return get(timerTask, releaseTtlValueReferenceAfterRun, false);\n    }\n\n    /**\n     * Factory method, wrap input {@link TimerTask} to {@link TtlTimerTask}.\n     * <p>\n     * This method is idempotent.\n     *\n     * @param timerTask                        input {@link TimerTask}\n     * @param releaseTtlValueReferenceAfterRun release TTL value reference after run, avoid memory leak even if {@link TtlTimerTask} is referred.\n     * @param idempotent                       is idempotent or not. {@code true} will cover up bugs! <b>DO NOT</b> set, only when you know why.\n     * @return Wrapped {@link TimerTask}\n     */\n    @Nullable\n    @Contract(value = \"null, _, _ -> null; !null, _, _ -> !null\", pure = true)\n    public static TtlTimerTask get(@Nullable TimerTask timerTask, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {\n        if (timerTask == null) return null;\n\n        if (timerTask instanceof TtlEnhanced) {\n            // avoid redundant decoration, and ensure idempotency\n            if (idempotent) return (TtlTimerTask) timerTask;\n            else throw new IllegalStateException(\"Already TtlTimerTask!\");\n        }\n        return new TtlTimerTask(timerTask, releaseTtlValueReferenceAfterRun);\n    }\n\n    /**\n     * Unwrap {@link TtlTimerTask} to the original/underneath one.\n     * <p>\n     * this method is {@code null}-safe, when input {@code TimerTask} parameter is {@code null}, return {@code null};\n     * if input {@code TimerTask} parameter is not a {@link TtlTimerTask} just return input {@code TimerTask}.\n     *\n     * @see #get(TimerTask)\n     * @since 2.10.2\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static TimerTask unwrap(@Nullable TimerTask timerTask) {\n        if (!(timerTask instanceof TtlTimerTask)) return timerTask;\n        else return ((TtlTimerTask) timerTask).getTimerTask();\n    }\n\n    /**\n     * Unwrap {@link TtlTimerTask} to the original/underneath one.\n     * <p>\n     * Invoke {@link #unwrap(TimerTask)} for each element in input collection.\n     * <p>\n     * This method is {@code null}-safe, when input {@code TimerTask} parameter is {@code null}, return a empty list.\n     *\n     * @see #unwrap(TimerTask)\n     * @since 2.10.2\n     */\n    @NonNull\n    public static List<TimerTask> unwraps(@Nullable Collection<? extends TimerTask> tasks) {\n        if (tasks == null) return Collections.emptyList();\n\n        List<TimerTask> copy = new ArrayList<>();\n        for (TimerTask task : tasks) {\n            if (!(task instanceof TtlTimerTask)) copy.add(task);\n            else copy.add(((TtlTimerTask) task).getTimerTask());\n        }\n        return copy;\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/TtlUnwrap.java",
    "content": "package com.alibaba.ttl;\n\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport org.jetbrains.annotations.Contract;\n\n/**\n * Util methods for TTL Wrapper: unwrap TTL Wrapper and check TTL Wrapper.\n * <p>\n * <b><i>Note:</i></b><br>\n * all methods are {@code null}-safe, when input parameter is {@code null}, return {@code null}.\n * <p>\n * <b><i>Implementation Note:</i></b><br>\n * The util methods in this class should have been inside {@link TtlWrappers}.<br>\n * But for {@code Java 6} support, it's required splitting the util methods\n * which involved {@code Java 8} from {@link TtlWrappers}.\n * In order to avoid loading {@code Java 8} class (eg: {@link java.util.function.Consumer}, {@link java.util.function.Supplier}),\n * when invoking any methods of {@link TtlWrappers}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see TtlRunnable\n * @see TtlCallable\n * @see com.alibaba.ttl.threadpool.TtlExecutors\n * @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper\n * @see TtlWrappers\n * @since 2.11.4\n */\npublic final class TtlUnwrap {\n    /**\n     * Generic unwrap method, unwrap {@link TtlWrapper} to the original/underneath one.\n     * <p>\n     * this method is {@code null}-safe, when input parameter is {@code null}, return {@code null};\n     * if input parameter is not a {@link TtlWrapper} just return input.\n     *\n     * @see TtlRunnable#unwrap(Runnable)\n     * @see TtlCallable#unwrap(java.util.concurrent.Callable)\n     * @see com.alibaba.ttl.threadpool.TtlExecutors#unwrap(java.util.concurrent.Executor)\n     * @see com.alibaba.ttl.threadpool.TtlExecutors#unwrap(java.util.concurrent.ThreadFactory)\n     * @see com.alibaba.ttl.threadpool.TtlExecutors#unwrap(java.util.Comparator)\n     * @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper#unwrap(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory)\n     * @see TtlWrappers#wrapSupplier(java.util.function.Supplier)\n     * @see TtlWrappers#wrapConsumer(java.util.function.Consumer)\n     * @see TtlWrappers#wrapBiConsumer(java.util.function.BiConsumer)\n     * @see TtlWrappers#wrapFunction(java.util.function.Function)\n     * @see TtlWrappers#wrapBiFunction(java.util.function.BiFunction)\n     * @see #isWrapper(Object)\n     * @since 2.11.4\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T unwrap(@Nullable T obj) {\n        if (!isWrapper(obj)) return obj;\n        else return ((TtlWrapper<T>) obj).unwrap();\n    }\n\n    /**\n     * check the input object is a {@code TtlWrapper} or not.\n     *\n     * @see #unwrap(Object)\n     * @since 2.11.4\n     */\n    public static <T> boolean isWrapper(@Nullable T obj) {\n        return obj instanceof TtlWrapper;\n    }\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlUnwrap() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/TtlWrappers.java",
    "content": "package com.alibaba.ttl;\n\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.function.*;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.*;\n\n/**\n * Util methods for TTL Wrapper: wrap common {@code Functional Interface}.\n * <p>\n * <b><i>Note:</i></b>\n * <ul>\n * <li>all methods is {@code null}-safe, when input parameter is {@code null}, return {@code null}.</li>\n * <li>all wrap method skip wrap (aka. just return input parameter), when input parameter is already wrapped.</li>\n * </ul>\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author huangfei1101 (fei.hf at alibaba-inc dot com)\n * @see TtlRunnable\n * @see TtlCallable\n * @see TtlUnwrap\n * @see TtlWrapper\n * @since 2.11.4\n */\npublic final class TtlWrappers {\n    /**\n     * wrap {@link Supplier} to TTL wrapper.\n     *\n     * @param supplier input {@link Supplier}\n     * @return Wrapped {@link Supplier}\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.12.4\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T> Supplier<T> wrapSupplier(@Nullable Supplier<T> supplier) {\n        if (supplier == null) return null;\n        else if (supplier instanceof TtlEnhanced) return supplier;\n        else return new TtlSupplier<>(supplier);\n    }\n\n    /**\n     * wrap {@link Supplier} to TTL wrapper.\n     *\n     * @param supplier input {@link Supplier}\n     * @return Wrapped {@link Supplier}\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.11.4\n     * @deprecated overload methods using the same name {@code wrap} is not readable\n     * and have the type inference problems in some case;\n     * so use {@link TtlWrappers#wrapSupplier(Supplier)} instead.\n     */\n    @Deprecated\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T> Supplier<T> wrap(@Nullable Supplier<T> supplier) {\n        return wrapSupplier(supplier);\n    }\n\n    private static class TtlSupplier<T> implements Supplier<T>, TtlWrapper<Supplier<T>>, TtlEnhanced {\n        final Supplier<T> supplier;\n        final Object captured;\n\n        TtlSupplier(@NonNull Supplier<T> supplier) {\n            this.supplier = supplier;\n            this.captured = capture();\n        }\n\n        @Override\n        public T get() {\n            final Object backup = replay(captured);\n            try {\n                return supplier.get();\n            } finally {\n                restore(backup);\n            }\n        }\n\n        @NonNull\n        @Override\n        public Supplier<T> unwrap() {\n            return supplier;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            TtlSupplier<?> that = (TtlSupplier<?>) o;\n\n            return supplier.equals(that.supplier);\n        }\n\n        @Override\n        public int hashCode() {\n            return supplier.hashCode();\n        }\n\n        @Override\n        public String toString() {\n            return this.getClass().getName() + \" - \" + supplier.toString();\n        }\n    }\n\n\n    /**\n     * wrap {@link Consumer} to TTL wrapper.\n     *\n     * @param consumer input {@link Consumer}\n     * @return Wrapped {@link Consumer}\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.12.4\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T> Consumer<T> wrapConsumer(@Nullable Consumer<T> consumer) {\n        if (consumer == null) return null;\n        else if (consumer instanceof TtlEnhanced) return consumer;\n        else return new TtlConsumer<>(consumer);\n    }\n\n    /**\n     * wrap {@link Consumer} to TTL wrapper.\n     *\n     * @param consumer input {@link Consumer}\n     * @return Wrapped {@link Consumer}\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.11.4\n     * @deprecated overload methods using the same name {@code wrap} is not readable\n     * and have the type inference problems in some case;\n     * so use {@link TtlWrappers#wrapConsumer(java.util.function.Consumer)} instead.\n     */\n    @Deprecated\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T> Consumer<T> wrap(@Nullable Consumer<T> consumer) {\n        return wrapConsumer(consumer);\n    }\n\n    private static class TtlConsumer<T> implements Consumer<T>, TtlWrapper<Consumer<T>>, TtlEnhanced {\n        final Consumer<T> consumer;\n        final Object captured;\n\n        TtlConsumer(@NonNull Consumer<T> consumer) {\n            this.consumer = consumer;\n            this.captured = capture();\n        }\n\n        @Override\n        public void accept(T t) {\n            final Object backup = replay(captured);\n            try {\n                consumer.accept(t);\n            } finally {\n                restore(backup);\n            }\n        }\n\n        @NonNull\n        @Override\n        public Consumer<T> unwrap() {\n            return consumer;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            TtlConsumer<?> that = (TtlConsumer<?>) o;\n\n            return consumer.equals(that.consumer);\n        }\n\n        @Override\n        public int hashCode() {\n            return consumer.hashCode();\n        }\n\n        @Override\n        public String toString() {\n            return this.getClass().getName() + \" - \" + consumer.toString();\n        }\n    }\n\n\n    /**\n     * wrap {@link BiConsumer} to TTL wrapper.\n     *\n     * @param consumer input {@link BiConsumer}\n     * @return Wrapped {@link BiConsumer}\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.12.4\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T, U> BiConsumer<T, U> wrapBiConsumer(@Nullable BiConsumer<T, U> consumer) {\n        if (consumer == null) return null;\n        else if (consumer instanceof TtlEnhanced) return consumer;\n        else return new TtlBiConsumer<>(consumer);\n    }\n\n    /**\n     * wrap input {@link BiConsumer} to TTL wrapper.\n     *\n     * @param consumer input {@link BiConsumer}\n     * @return Wrapped {@link BiConsumer}\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.11.4\n     * @deprecated overload methods using the same name {@code wrap} is not readable\n     * and have the type inference problems in some case;\n     * so use {@link TtlWrappers#wrapBiConsumer(BiConsumer)} instead.\n     */\n    @Deprecated\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T, U> BiConsumer<T, U> wrap(@Nullable BiConsumer<T, U> consumer) {\n        return wrapBiConsumer(consumer);\n    }\n\n    private static class TtlBiConsumer<T, U> implements BiConsumer<T, U>, TtlWrapper<BiConsumer<T, U>>, TtlEnhanced {\n        final BiConsumer<T, U> consumer;\n        final Object captured;\n\n        TtlBiConsumer(@NonNull BiConsumer<T, U> consumer) {\n            this.consumer = consumer;\n            this.captured = capture();\n        }\n\n        @Override\n        public void accept(T t, U u) {\n            final Object backup = replay(captured);\n            try {\n                consumer.accept(t, u);\n            } finally {\n                restore(backup);\n            }\n        }\n\n        @NonNull\n        @Override\n        public BiConsumer<T, U> unwrap() {\n            return consumer;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            TtlBiConsumer<?, ?> that = (TtlBiConsumer<?, ?>) o;\n\n            return consumer.equals(that.consumer);\n        }\n\n        @Override\n        public int hashCode() {\n            return consumer.hashCode();\n        }\n\n        @Override\n        public String toString() {\n            return this.getClass().getName() + \" - \" + consumer.toString();\n        }\n    }\n\n\n    /**\n     * wrap {@link Function} to TTL wrapper.\n     *\n     * @param fn input {@link Function}\n     * @return Wrapped {@link Function}\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.12.4\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T, R> Function<T, R> wrapFunction(@Nullable Function<T, R> fn) {\n        if (fn == null) return null;\n        else if (fn instanceof TtlEnhanced) return fn;\n        else return new TtlFunction<>(fn);\n    }\n\n    /**\n     * wrap {@link Function} to TTL wrapper.\n     *\n     * @param fn input {@link Function}\n     * @return Wrapped {@link Function}\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.11.4\n     * @deprecated overload methods using the same name {@code wrap} is not readable\n     * and have the type inference problems in some case;\n     * so use {@link TtlWrappers#wrapFunction(Function)} instead.\n     */\n    @Deprecated\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T, R> Function<T, R> wrap(@Nullable Function<T, R> fn) {\n        return wrapFunction(fn);\n    }\n\n    private static class TtlFunction<T, R> implements Function<T, R>, TtlWrapper<Function<T, R>>, TtlEnhanced {\n        final Function<T, R> fn;\n        final Object captured;\n\n        TtlFunction(@NonNull Function<T, R> fn) {\n            this.fn = fn;\n            this.captured = capture();\n        }\n\n        @Override\n        public R apply(T t) {\n            final Object backup = replay(captured);\n            try {\n                return fn.apply(t);\n            } finally {\n                restore(backup);\n            }\n        }\n\n        @NonNull\n        @Override\n        public Function<T, R> unwrap() {\n            return fn;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            TtlFunction<?, ?> that = (TtlFunction<?, ?>) o;\n\n            return fn.equals(that.fn);\n        }\n\n        @Override\n        public int hashCode() {\n            return fn.hashCode();\n        }\n\n        @Override\n        public String toString() {\n            return this.getClass().getName() + \" - \" + fn.toString();\n        }\n    }\n\n\n    /**\n     * wrap {@link BiFunction} to TTL wrapper.\n     *\n     * @param fn input {@link BiFunction}\n     * @return Wrapped {@link BiFunction}\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.12.4\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T, U, R> BiFunction<T, U, R> wrapBiFunction(@Nullable BiFunction<T, U, R> fn) {\n        if (fn == null) return null;\n        else if (fn instanceof TtlEnhanced) return fn;\n        else return new TtlBiFunction<>(fn);\n    }\n\n    /**\n     * wrap {@link BiFunction} to TTL wrapper.\n     *\n     * @param fn input {@link BiFunction}\n     * @return Wrapped {@link BiFunction}\n     * @see TtlUnwrap#unwrap(Object)\n     * @since 2.11.4\n     * @deprecated overload methods using the same name {@code wrap} is not readable\n     * and have the type inference problems in some case;\n     * so use {@link TtlWrappers#wrapBiFunction(BiFunction)} instead.\n     */\n    @Deprecated\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static <T, U, R> BiFunction<T, U, R> wrap(@Nullable BiFunction<T, U, R> fn) {\n        return wrapBiFunction(fn);\n    }\n\n    private static class TtlBiFunction<T, U, R> implements BiFunction<T, U, R>, TtlWrapper<BiFunction<T, U, R>>, TtlEnhanced {\n        final BiFunction<T, U, R> fn;\n        final Object captured;\n\n        TtlBiFunction(@NonNull BiFunction<T, U, R> fn) {\n            this.fn = fn;\n            this.captured = capture();\n        }\n\n        @Override\n        public R apply(T t, U u) {\n            final Object backup = replay(captured);\n            try {\n                return fn.apply(t, u);\n            } finally {\n                restore(backup);\n            }\n        }\n\n        @NonNull\n        @Override\n        public BiFunction<T, U, R> unwrap() {\n            return fn;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o == null || getClass() != o.getClass()) return false;\n\n            TtlBiFunction<?, ?, ?> that = (TtlBiFunction<?, ?, ?>) o;\n\n            return fn.equals(that.fn);\n        }\n\n        @Override\n        public int hashCode() {\n            return fn.hashCode();\n        }\n\n        @Override\n        public String toString() {\n            return this.getClass().getName() + \" - \" + fn.toString();\n        }\n    }\n\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlWrappers() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/package-info.java",
    "content": "/**\n * TTL API.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.TransmittableThreadLocal\n * @see com.alibaba.ttl.TtlRunnable\n * @see com.alibaba.ttl.TtlCallable\n * @see com.alibaba.ttl.TtlUnwrap\n * @see com.alibaba.ttl.TtlWrappers\n */\npackage com.alibaba.ttl;\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/spi/TtlAttachments.java",
    "content": "package com.alibaba.ttl.spi;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\n/**\n * The TTL attachments for TTL tasks,\n * eg: {@link com.alibaba.ttl.TtlRunnable}, {@link com.alibaba.ttl.TtlCallable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 2.11.0\n */\npublic interface TtlAttachments extends TtlEnhanced {\n    /**\n     * set the TTL attachments for TTL tasks\n     *\n     * @param key   attachment key\n     * @param value attachment value\n     * @since 2.11.0\n     */\n    void setTtlAttachment(@NonNull String key, Object value);\n\n    /**\n     * get the TTL attachment for TTL tasks\n     *\n     * @param key attachment key\n     * @since 2.11.0\n     */\n    <T> T getTtlAttachment(@NonNull String key);\n\n    /**\n     * The attachment key of TTL task, weather this task is a auto wrapper task.\n     * <p>\n     * so the value of this attachment is a {@code boolean}.\n     *\n     * @since 2.11.0\n     */\n    String KEY_IS_AUTO_WRAPPER = \"ttl.is.auto.wrapper\";\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/spi/TtlAttachmentsDelegate.java",
    "content": "package com.alibaba.ttl.spi;\n\nimport com.alibaba.ttl.TtlUnwrap;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * {@link TtlAttachments} delegate/implementation.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.TtlRunnable\n * @see com.alibaba.ttl.TtlCallable\n * @since 2.11.0\n */\npublic class TtlAttachmentsDelegate implements TtlAttachments {\n    private final ConcurrentMap<String, Object> attachments = new ConcurrentHashMap<>();\n\n    @Override\n    public void setTtlAttachment(@NonNull String key, Object value) {\n        attachments.put(key, value);\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> T getTtlAttachment(@NonNull String key) {\n        return (T) attachments.get(key);\n    }\n\n    // ======== AutoWrapper Util Methods ========\n\n    /**\n     * @see TtlAttachments#KEY_IS_AUTO_WRAPPER\n     * @since 3.0.0\n     */\n    public static boolean isAutoWrapper(@Nullable Object ttlAttachments) {\n        if (!(ttlAttachments instanceof TtlAttachments)) return false;\n\n        final Boolean value = ((TtlAttachments) ttlAttachments).getTtlAttachment(KEY_IS_AUTO_WRAPPER);\n        if (value == null) return false;\n\n        return value;\n    }\n\n    /**\n     * @see TtlAttachments#KEY_IS_AUTO_WRAPPER\n     * @since 3.0.0\n     */\n    public static void setAutoWrapperAttachment(@Nullable Object ttlAttachment) {\n        if (!(ttlAttachment instanceof TtlAttachments)) return;\n\n        ((TtlAttachments) ttlAttachment).setTtlAttachment(TtlAttachments.KEY_IS_AUTO_WRAPPER, true);\n    }\n\n    /**\n     * @see TtlAttachments#KEY_IS_AUTO_WRAPPER\n     * @since 3.0.0\n     */\n    @Nullable\n    public static <T> T unwrapIfIsAutoWrapper(@Nullable T obj) {\n        if (isAutoWrapper(obj)) return TtlUnwrap.unwrap(obj);\n        else return obj;\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/spi/TtlEnhanced.java",
    "content": "package com.alibaba.ttl.spi;\n\n/**\n * a Ttl marker/tag interface, for ttl enhanced class, for example {@code TTL wrapper}\n * like {@link com.alibaba.ttl.TtlRunnable}, {@link com.alibaba.ttl.TtlCallable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.TtlRunnable\n * @see com.alibaba.ttl.TtlCallable\n * @see com.alibaba.ttl.TtlRecursiveAction\n * @see com.alibaba.ttl.TtlRecursiveTask\n * @see TtlAttachments\n * @since 2.11.0\n */\npublic interface TtlEnhanced {\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/spi/TtlWrapper.java",
    "content": "package com.alibaba.ttl.spi;\n\nimport com.alibaba.ttl.TtlUnwrap;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\n/**\n * Ttl Wrapper interface.\n * <p>\n * Used to mark wrapper types, for example:\n * <ul>\n *     <li>{@link com.alibaba.ttl.TtlCallable}</li>\n *     <li>{@link com.alibaba.ttl.threadpool.TtlExecutors}</li>\n *     <li>{@link com.alibaba.ttl.threadpool.DisableInheritableThreadFactory}</li>\n * </ul>\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see TtlUnwrap#unwrap\n * @see com.alibaba.ttl.TtlCallable\n * @see com.alibaba.ttl.TtlRunnable\n * @see com.alibaba.ttl.threadpool.TtlExecutors\n * @see com.alibaba.ttl.threadpool.DisableInheritableThreadFactory\n * @see com.alibaba.ttl.threadpool.DisableInheritableForkJoinWorkerThreadFactory\n * @since 2.11.4\n */\npublic interface TtlWrapper<T> extends TtlEnhanced {\n    /**\n     * unwrap {@link TtlWrapper} to the original/underneath one.\n     *\n     * @see TtlUnwrap#unwrap(Object)\n     */\n    @NonNull\n    T unwrap();\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/spi/package-info.java",
    "content": "/**\n * TTL SPI\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.spi.TtlEnhanced\n * @see com.alibaba.ttl.spi.TtlAttachments\n * @since 2.11.0\n */\npackage com.alibaba.ttl.spi;\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/ComparableComparator.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage com.alibaba.ttl.threadpool;\n\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n// This source code file is copied and small adopted from commons-collections4 4.4:\n//\n// https://github.com/apache/commons-collections/blob/commons-commons-collections-4.4/src/main/java/org/apache/commons/collections4/comparators/ComparableComparator.java\n//\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\nimport java.io.Serializable;\nimport java.util.Comparator;\n\n/**\n * A {@link Comparator Comparator} that compares {@link Comparable Comparable}\n * objects.\n * <p>\n * This Comparator is useful, for example, for enforcing the natural order in\n * custom implementations of {@link java.util.SortedSet SortedSet} and\n * {@link java.util.SortedMap SortedMap}.\n * </p>\n * <p>\n * Note: In the 2.0 and 2.1 releases of Commons Collections, this class would\n * throw a {@link ClassCastException} if either of the arguments to\n * {@link #compare compare} were <code>null</code>, not\n * {@link Comparable Comparable}, or for which\n * {@link Comparable#compareTo(Object) compareTo} gave inconsistent results.\n * This is no longer the case. See {@link #compare compare} for\n * details.\n * </p>\n *\n * @param <E> the type of objects compared by this comparator\n *\n * @since 2.0\n * @see java.util.Collections#reverseOrder()\n */\nclass ComparableComparator<E extends Comparable<? super E>> implements Comparator<E>, Serializable {\n\n    /** Serialization version. */\n    private static final long serialVersionUID=-291439688585137865L;\n\n    /** The singleton instance. */\n    @SuppressWarnings(\"rawtypes\")\n    public static final ComparableComparator INSTANCE = new ComparableComparator();\n\n    //-----------------------------------------------------------------------\n    /**\n     * Gets the singleton instance of a ComparableComparator.\n     * <p>\n     * Developers are encouraged to use the comparator returned from this method\n     * instead of constructing a new instance to reduce allocation and GC overhead\n     * when multiple comparable comparators may be used in the same VM.\n     *\n     * @param <E>  the element type\n     * @return the singleton ComparableComparator\n     * @since 4.0\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <E extends Comparable<? super E>> ComparableComparator<E> comparableComparator() {\n        return INSTANCE;\n    }\n\n    //-----------------------------------------------------------------------\n    /**\n     * Constructor whose use should be avoided.\n     * <p>\n     * Please use the {@link #comparableComparator()} method whenever possible.\n     */\n    public ComparableComparator() {\n        super();\n    }\n\n    //-----------------------------------------------------------------------\n    /**\n     * Compare the two {@link Comparable Comparable} arguments.\n     * This method is equivalent to:\n     * <pre>((Comparable)obj1).compareTo(obj2)</pre>\n     *\n     * @param obj1  the first object to compare\n     * @param obj2  the second object to compare\n     * @return negative if obj1 is less, positive if greater, zero if equal\n     * @throws NullPointerException if <i>obj1</i> is <code>null</code>,\n     *         or when <code>((Comparable)obj1).compareTo(obj2)</code> does\n     * @throws ClassCastException if <i>obj1</i> is not a <code>Comparable</code>,\n     *         or when <code>((Comparable)obj1).compareTo(obj2)</code> does\n     */\n    @Override\n    public int compare(final E obj1, final E obj2) {\n        return obj1.compareTo(obj2);\n    }\n\n    //-----------------------------------------------------------------------\n    /**\n     * Implement a hash code for this comparator that is consistent with\n     * {@link #equals(Object) equals}.\n     *\n     * @return a hash code for this comparator.\n     * @since 3.0\n     */\n    @Override\n    public int hashCode() {\n        return \"ComparableComparator\".hashCode();\n    }\n\n    /**\n     * Returns {@code true} iff <i>that</i> Object is a {@link Comparator Comparator}\n     * whose ordering is known to be equivalent to mine.\n     * <p>\n     * This implementation returns {@code true} iff\n     * <code><i>object</i>.{@link Object#getClass() getClass()}</code> equals\n     * <code>this.getClass()</code>. Subclasses may want to override this behavior to remain\n     * consistent with the {@link Comparator#equals(Object)} contract.\n     *\n     * @param object  the object to compare with\n     * @return {@code true} if equal\n     * @since 3.0\n     */\n    @Override\n    public boolean equals(final Object object) {\n        return this == object ||\n               null != object && object.getClass().equals(this.getClass());\n    }\n\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java",
    "content": "package com.alibaba.ttl.threadpool;\n\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;\n\n/**\n * Disable inheritable {@link ForkJoinWorkerThreadFactory}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 2.10.1\n */\npublic interface DisableInheritableForkJoinWorkerThreadFactory extends ForkJoinWorkerThreadFactory, TtlWrapper<ForkJoinWorkerThreadFactory> {\n    /**\n     * Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one.\n     */\n    @NonNull\n    @Override\n    ForkJoinWorkerThreadFactory unwrap();\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactoryWrapper.java",
    "content": "package com.alibaba.ttl.threadpool;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;\nimport java.util.concurrent.ForkJoinWorkerThread;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.clear;\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.restore;\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 2.10.1\n */\nclass DisableInheritableForkJoinWorkerThreadFactoryWrapper implements DisableInheritableForkJoinWorkerThreadFactory {\n    private final ForkJoinWorkerThreadFactory threadFactory;\n\n    DisableInheritableForkJoinWorkerThreadFactoryWrapper(@NonNull ForkJoinWorkerThreadFactory threadFactory) {\n        this.threadFactory = threadFactory;\n    }\n\n    @Override\n    public ForkJoinWorkerThread newThread(ForkJoinPool pool) {\n        final Object backup = clear();\n        try {\n            return threadFactory.newThread(pool);\n        } finally {\n            restore(backup);\n        }\n    }\n\n    @Override\n    @NonNull\n    public ForkJoinWorkerThreadFactory unwrap() {\n        return threadFactory;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        DisableInheritableForkJoinWorkerThreadFactoryWrapper that = (DisableInheritableForkJoinWorkerThreadFactoryWrapper) o;\n\n        return threadFactory.equals(that.threadFactory);\n    }\n\n    @Override\n    public int hashCode() {\n        return threadFactory.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + threadFactory.toString();\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java",
    "content": "package com.alibaba.ttl.threadpool;\n\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.concurrent.ThreadFactory;\n\n/**\n * Disable inheritable {@link ThreadFactory}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see ThreadFactory\n * @since 2.10.0\n */\npublic interface DisableInheritableThreadFactory extends ThreadFactory, TtlWrapper<ThreadFactory> {\n    /**\n     * Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one.\n     */\n    @NonNull\n    @Override\n    ThreadFactory unwrap();\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactoryWrapper.java",
    "content": "package com.alibaba.ttl.threadpool;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.concurrent.ThreadFactory;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.clear;\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.restore;\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 2.10.0\n */\nclass DisableInheritableThreadFactoryWrapper implements DisableInheritableThreadFactory {\n    private final ThreadFactory threadFactory;\n\n    DisableInheritableThreadFactoryWrapper(@NonNull ThreadFactory threadFactory) {\n        this.threadFactory = threadFactory;\n    }\n\n    @Override\n    public Thread newThread(@NonNull Runnable r) {\n        final Object backup = clear();\n        try {\n            return threadFactory.newThread(r);\n        } finally {\n            restore(backup);\n        }\n    }\n\n    @NonNull\n    @Override\n    public ThreadFactory unwrap() {\n        return threadFactory;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        DisableInheritableThreadFactoryWrapper that = (DisableInheritableThreadFactoryWrapper) o;\n\n        return threadFactory.equals(that.threadFactory);\n    }\n\n    @Override\n    public int hashCode() {\n        return threadFactory.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + threadFactory.toString();\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/ExecutorServiceTtlWrapper.java",
    "content": "package com.alibaba.ttl.threadpool;\n\nimport com.alibaba.ttl.TransmittableThreadLocal;\nimport com.alibaba.ttl.TtlCallable;\nimport com.alibaba.ttl.TtlRunnable;\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.*;\n\n/**\n * {@link TransmittableThreadLocal} Wrapper of {@link ExecutorService},\n * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link Callable}\n * to the execution time of {@link Runnable} or {@link Callable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 0.9.0\n */\n@SuppressFBWarnings({\"EQ_DOESNT_OVERRIDE_EQUALS\"})\nclass ExecutorServiceTtlWrapper extends ExecutorTtlWrapper implements ExecutorService, TtlEnhanced {\n    private final ExecutorService executorService;\n\n    ExecutorServiceTtlWrapper(@NonNull ExecutorService executorService, boolean idempotent) {\n        super(executorService, idempotent);\n        this.executorService = executorService;\n    }\n\n    @Override\n    public void shutdown() {\n        executorService.shutdown();\n    }\n\n    @NonNull\n    @Override\n    public List<Runnable> shutdownNow() {\n        return executorService.shutdownNow();\n    }\n\n    @Override\n    public boolean isShutdown() {\n        return executorService.isShutdown();\n    }\n\n    @Override\n    public boolean isTerminated() {\n        return executorService.isTerminated();\n    }\n\n    @Override\n    public boolean awaitTermination(long timeout, @NonNull TimeUnit unit) throws InterruptedException {\n        return executorService.awaitTermination(timeout, unit);\n    }\n\n    @NonNull\n    @Override\n    public <T> Future<T> submit(@NonNull Callable<T> task) {\n        return executorService.submit(TtlCallable.get(task, false, idempotent));\n    }\n\n    @NonNull\n    @Override\n    public <T> Future<T> submit(@NonNull Runnable task, T result) {\n        return executorService.submit(TtlRunnable.get(task, false, idempotent), result);\n    }\n\n    @NonNull\n    @Override\n    public Future<?> submit(@NonNull Runnable task) {\n        return executorService.submit(TtlRunnable.get(task, false, idempotent));\n    }\n\n    @NonNull\n    @Override\n    public <T> List<Future<T>> invokeAll(@NonNull Collection<? extends Callable<T>> tasks) throws InterruptedException {\n        return executorService.invokeAll(TtlCallable.gets(tasks, false, idempotent));\n    }\n\n    @NonNull\n    @Override\n    public <T> List<Future<T>> invokeAll(@NonNull Collection<? extends Callable<T>> tasks, long timeout, @NonNull TimeUnit unit) throws InterruptedException {\n        return executorService.invokeAll(TtlCallable.gets(tasks, false, idempotent), timeout, unit);\n    }\n\n    @NonNull\n    @Override\n    public <T> T invokeAny(@NonNull Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {\n        return executorService.invokeAny(TtlCallable.gets(tasks, false, idempotent));\n    }\n\n    @Override\n    public <T> T invokeAny(@NonNull Collection<? extends Callable<T>> tasks, long timeout, @NonNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {\n        return executorService.invokeAny(TtlCallable.gets(tasks, false, idempotent), timeout, unit);\n    }\n\n    @NonNull\n    @Override\n    public ExecutorService unwrap() {\n        return executorService;\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/ExecutorTtlWrapper.java",
    "content": "package com.alibaba.ttl.threadpool;\n\nimport com.alibaba.ttl.TransmittableThreadLocal;\nimport com.alibaba.ttl.TtlRunnable;\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.concurrent.Executor;\n\n/**\n * {@link TransmittableThreadLocal} Wrapper of {@link Executor},\n * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable}\n * to the execution time of {@link Runnable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 0.9.0\n */\nclass ExecutorTtlWrapper implements Executor, TtlWrapper<Executor>, TtlEnhanced {\n    private final Executor executor;\n    protected final boolean idempotent;\n\n    ExecutorTtlWrapper(@NonNull Executor executor, boolean idempotent) {\n        this.executor = executor;\n        this.idempotent = idempotent;\n    }\n\n    @Override\n    public void execute(@NonNull Runnable command) {\n        executor.execute(TtlRunnable.get(command, false, idempotent));\n    }\n\n    @NonNull\n    @Override\n    public Executor unwrap() {\n        return executor;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        ExecutorTtlWrapper that = (ExecutorTtlWrapper) o;\n\n        return executor.equals(that.executor);\n    }\n\n    @Override\n    public int hashCode() {\n        return executor.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return this.getClass().getName() + \" - \" + executor;\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/ScheduledExecutorServiceTtlWrapper.java",
    "content": "package com.alibaba.ttl.threadpool;\n\nimport com.alibaba.ttl.TransmittableThreadLocal;\nimport com.alibaba.ttl.TtlCallable;\nimport com.alibaba.ttl.TtlRunnable;\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * {@link TransmittableThreadLocal} Wrapper of {@link ScheduledExecutorService},\n * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link Callable}\n * to the execution time of {@link Runnable} or {@link Callable}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 0.9.0\n */\n@SuppressFBWarnings({\"EQ_DOESNT_OVERRIDE_EQUALS\"})\nclass ScheduledExecutorServiceTtlWrapper extends ExecutorServiceTtlWrapper implements ScheduledExecutorService, TtlEnhanced {\n    final ScheduledExecutorService scheduledExecutorService;\n\n    public ScheduledExecutorServiceTtlWrapper(@NonNull ScheduledExecutorService scheduledExecutorService, boolean idempotent) {\n        super(scheduledExecutorService, idempotent);\n        this.scheduledExecutorService = scheduledExecutorService;\n    }\n\n    @NonNull\n    @Override\n    public ScheduledFuture<?> schedule(@NonNull Runnable command, long delay, @NonNull TimeUnit unit) {\n        return scheduledExecutorService.schedule(TtlRunnable.get(command, false, idempotent), delay, unit);\n    }\n\n    @NonNull\n    @Override\n    public <V> ScheduledFuture<V> schedule(@NonNull Callable<V> callable, long delay, @NonNull TimeUnit unit) {\n        return scheduledExecutorService.schedule(TtlCallable.get(callable, false, idempotent), delay, unit);\n    }\n\n    @NonNull\n    @Override\n    public ScheduledFuture<?> scheduleAtFixedRate(@NonNull Runnable command, long initialDelay, long period, @NonNull TimeUnit unit) {\n        return scheduledExecutorService.scheduleAtFixedRate(TtlRunnable.get(command, false, idempotent), initialDelay, period, unit);\n    }\n\n    @NonNull\n    @Override\n    public ScheduledFuture<?> scheduleWithFixedDelay(@NonNull Runnable command, long initialDelay, long delay, @NonNull TimeUnit unit) {\n        return scheduledExecutorService.scheduleWithFixedDelay(TtlRunnable.get(command, false, idempotent), initialDelay, delay, unit);\n    }\n\n    @NonNull\n    @Override\n    public ScheduledExecutorService unwrap() {\n        return scheduledExecutorService;\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/TtlExecutors.java",
    "content": "package com.alibaba.ttl.threadpool;\n\nimport com.alibaba.ttl.TransmittableThreadLocal;\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport com.alibaba.ttl.threadpool.agent.TtlAgent;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.Comparator;\nimport java.util.concurrent.*;\n\n/**\n * Util methods for TTL wrapper of jdk executors.\n *\n * <ol>\n *     <li>wrap/check/unwrap methods for TTL wrapper of jdk executors({@link Executor}, {@link ExecutorService}, {@link ScheduledExecutorService}).</li>\n *     <li>wrap/check/unwrap methods for disable Inheritable wrapper of {@link ThreadFactory}.</li>\n *     <li>wrap/check/unwrap methods for {@code TtlRunnableUnwrapComparator} wrapper of {@link PriorityBlockingQueue}.</li>\n * </ol>\n * <p>\n * <b><i>Note:</i></b>\n * <ul>\n * <li>all method is {@code null}-safe.\n * for wrap/unwrap methods when input parameter is {@code null}, return {@code null}.\n * for check methods when input parameter is {@code null}, return {@code false}.</li>\n * <li>skip wrap/decoration thread pool/{@code executor}(aka. just return input {@code executor})\n * when ttl agent is loaded, Or when input {@code executor} is already wrapped/decorated.</li>\n * </ul>\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see Executor\n * @see ExecutorService\n * @see ScheduledExecutorService\n * @see ThreadPoolExecutor\n * @see ScheduledThreadPoolExecutor\n * @see Executors\n * @see java.util.concurrent.CompletionService\n * @see java.util.concurrent.ExecutorCompletionService\n * @see ThreadFactory\n * @see Executors#defaultThreadFactory()\n * @see PriorityBlockingQueue\n * @see TtlForkJoinPoolHelper\n * @since 0.9.0\n */\npublic final class TtlExecutors {\n    /**\n     * {@link TransmittableThreadLocal} Wrapper of {@link Executor},\n     * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable}\n     * to the execution time of {@link Runnable}.\n     * <p>\n     * NOTE: sine v2.12.0 the idempotency of return wrapped Executor is changed to true,\n     * so the wrapped Executor can be cooperated with the usage of \"Decorate Runnable and Callable\".\n     * <p>\n     * About idempotency: if is idempotent,\n     * it's allowed to submit the {@link com.alibaba.ttl.TtlRunnable}/{@link com.alibaba.ttl.TtlCallable} to the wrapped Executor;\n     * otherwise throw {@link IllegalStateException}.\n     *\n     * @param executor input Executor\n     * @return wrapped Executor\n     * @see com.alibaba.ttl.TtlRunnable#get(Runnable, boolean, boolean)\n     * @see com.alibaba.ttl.TtlCallable#get(Callable, boolean, boolean)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static Executor getTtlExecutor(@Nullable Executor executor) {\n        if (TtlAgent.isTtlAgentLoaded() || executor == null || executor instanceof TtlEnhanced) {\n            return executor;\n        }\n        return new ExecutorTtlWrapper(executor, true);\n    }\n\n    /**\n     * {@link TransmittableThreadLocal} Wrapper of {@link ExecutorService},\n     * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link java.util.concurrent.Callable}\n     * to the execution time of {@link Runnable} or {@link java.util.concurrent.Callable}.\n     * <p>\n     * NOTE: sine v2.12.0 the idempotency of return wrapped ExecutorService is changed to true,\n     * so the wrapped ExecutorService can be cooperated with the usage of \"Decorate Runnable and Callable\".\n     * <p>\n     * About idempotency: if is idempotent,\n     * it's allowed to submit the {@link com.alibaba.ttl.TtlRunnable}/{@link com.alibaba.ttl.TtlCallable} to the wrapped ExecutorService;\n     * otherwise throw {@link IllegalStateException}.\n     *\n     * @param executorService input ExecutorService\n     * @return wrapped ExecutorService\n     * @see com.alibaba.ttl.TtlRunnable#get(Runnable, boolean, boolean)\n     * @see com.alibaba.ttl.TtlCallable#get(Callable, boolean, boolean)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ExecutorService getTtlExecutorService(@Nullable ExecutorService executorService) {\n        if (TtlAgent.isTtlAgentLoaded() || executorService == null || executorService instanceof TtlEnhanced) {\n            return executorService;\n        }\n        return new ExecutorServiceTtlWrapper(executorService, true);\n    }\n\n\n    /**\n     * {@link TransmittableThreadLocal} Wrapper of {@link ScheduledExecutorService},\n     * transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link java.util.concurrent.Callable}\n     * to the execution time of {@link Runnable} or {@link java.util.concurrent.Callable}.\n     * <p>\n     * NOTE: sine v2.12.0 the idempotency of return wrapped ScheduledExecutorService is changed to true,\n     * so the wrapped ScheduledExecutorService can be cooperated with the usage of \"Decorate Runnable and Callable\".\n     * <p>\n     * About idempotency: if is idempotent,\n     * it's allowed to submit the {@link com.alibaba.ttl.TtlRunnable}/{@link com.alibaba.ttl.TtlCallable} to the wrapped ScheduledExecutorService;\n     * otherwise throw {@link IllegalStateException}.\n     *\n     * @param scheduledExecutorService input scheduledExecutorService\n     * @return wrapped scheduledExecutorService\n     * @see com.alibaba.ttl.TtlRunnable#get(Runnable, boolean, boolean)\n     * @see com.alibaba.ttl.TtlCallable#get(Callable, boolean, boolean)\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ScheduledExecutorService getTtlScheduledExecutorService(@Nullable ScheduledExecutorService scheduledExecutorService) {\n        if (TtlAgent.isTtlAgentLoaded() || scheduledExecutorService == null || scheduledExecutorService instanceof TtlEnhanced) {\n            return scheduledExecutorService;\n        }\n        return new ScheduledExecutorServiceTtlWrapper(scheduledExecutorService, true);\n    }\n\n    /**\n     * check the executor is a TTL executor wrapper or not.\n     * <p>\n     * if the parameter executor is TTL wrapper, return {@code true}, otherwise {@code false}.\n     * <p>\n     * NOTE: if input executor is {@code null}, return {@code false}.\n     *\n     * @param executor input executor\n     * @param <T>      Executor type\n     * @see #getTtlExecutor(Executor)\n     * @see #getTtlExecutorService(ExecutorService)\n     * @see #getTtlScheduledExecutorService(ScheduledExecutorService)\n     * @see #unwrap(Executor)\n     * @since 2.8.0\n     */\n    public static <T extends Executor> boolean isTtlWrapper(@Nullable T executor) {\n        return executor instanceof TtlWrapper;\n    }\n\n    /**\n     * Unwrap TTL executor wrapper to the original/underneath one.\n     * <p>\n     * if the parameter executor is TTL wrapper, return the original/underneath executor;\n     * otherwise, just return the input parameter executor.\n     * <p>\n     * NOTE: if input executor is {@code null}, return {@code null}.\n     *\n     * @param executor input executor\n     * @param <T>      Executor type\n     * @see #getTtlExecutor(Executor)\n     * @see #getTtlExecutorService(ExecutorService)\n     * @see #getTtlScheduledExecutorService(ScheduledExecutorService)\n     * @see #isTtlWrapper(Executor)\n     * @see com.alibaba.ttl.TtlUnwrap#unwrap(Object)\n     * @since 2.8.0\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    @SuppressWarnings(\"unchecked\")\n    public static <T extends Executor> T unwrap(@Nullable T executor) {\n        if (!isTtlWrapper(executor)) return executor;\n\n        return (T) ((ExecutorTtlWrapper) executor).unwrap();\n    }\n\n    /**\n     * Wrapper of {@link ThreadFactory}, disable inheritable.\n     *\n     * @param threadFactory input thread factory\n     * @see DisableInheritableThreadFactory\n     * @see TtlForkJoinPoolHelper#getDisableInheritableForkJoinWorkerThreadFactory\n     * @since 2.10.0\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ThreadFactory getDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) {\n        if (threadFactory == null || isDisableInheritableThreadFactory(threadFactory)) return threadFactory;\n\n        return new DisableInheritableThreadFactoryWrapper(threadFactory);\n    }\n\n    /**\n     * Wrapper of {@link Executors#defaultThreadFactory()}, disable inheritable.\n     *\n     * @see #getDisableInheritableThreadFactory(ThreadFactory)\n     * @see TtlForkJoinPoolHelper#getDefaultDisableInheritableForkJoinWorkerThreadFactory()\n     * @since 2.10.0\n     */\n    @NonNull\n    public static ThreadFactory getDefaultDisableInheritableThreadFactory() {\n        return getDisableInheritableThreadFactory(Executors.defaultThreadFactory());\n    }\n\n    /**\n     * check the {@link ThreadFactory} is {@link DisableInheritableThreadFactory} or not.\n     *\n     * @see TtlForkJoinPoolHelper#getDisableInheritableForkJoinWorkerThreadFactory\n     * @see #getDefaultDisableInheritableThreadFactory()\n     * @see DisableInheritableThreadFactory\n     * @since 2.10.0\n     */\n    public static boolean isDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) {\n        return threadFactory instanceof DisableInheritableThreadFactory;\n    }\n\n    /**\n     * Unwrap {@link DisableInheritableThreadFactory} to the original/underneath one.\n     *\n     * @see #getDisableInheritableThreadFactory(ThreadFactory)\n     * @see #getDefaultDisableInheritableThreadFactory()\n     * @see #isDisableInheritableThreadFactory(ThreadFactory)\n     * @see TtlForkJoinPoolHelper#unwrap(ForkJoinPool.ForkJoinWorkerThreadFactory)\n     * @see DisableInheritableThreadFactory\n     * @see com.alibaba.ttl.TtlUnwrap#unwrap(Object)\n     * @since 2.10.0\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ThreadFactory unwrap(@Nullable ThreadFactory threadFactory) {\n        if (!isDisableInheritableThreadFactory(threadFactory)) return threadFactory;\n\n        return ((DisableInheritableThreadFactory) threadFactory).unwrap();\n    }\n\n    /**\n     * Wrapper of {@code Comparator<Runnable>} which unwrap {@link com.alibaba.ttl.TtlRunnable} before compare,\n     * aka {@code TtlRunnableUnwrapComparator}.\n     * <p>\n     * Prepared for {@code comparator} parameter of constructor\n     * {@link PriorityBlockingQueue#PriorityBlockingQueue(int, Comparator)}.\n     * <p>\n     * {@link PriorityBlockingQueue} can be used by constructor\n     * {@link ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue)}.\n     *\n     * @param comparator input comparator\n     * @return wrapped comparator\n     * @see ThreadPoolExecutor\n     * @see ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue)\n     * @see PriorityBlockingQueue\n     * @see PriorityBlockingQueue#PriorityBlockingQueue(int, Comparator)\n     * @since 2.12.3\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static Comparator<Runnable> getTtlRunnableUnwrapComparator(@Nullable Comparator<Runnable> comparator) {\n        if (comparator == null || isTtlRunnableUnwrapComparator(comparator)) return comparator;\n\n        return new TtlUnwrapComparator<>(comparator);\n    }\n\n    @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n    private static final Comparator INSTANCE = new TtlUnwrapComparator(ComparableComparator.INSTANCE);\n\n    /**\n     * {@code TtlRunnableUnwrapComparator} that compares {@link Comparable Comparable} objects.\n     *\n     * @see #getTtlRunnableUnwrapComparator(Comparator)\n     * @since 2.12.3\n     */\n    @NonNull\n    @SuppressWarnings(\"unchecked\")\n    public static Comparator<Runnable> getTtlRunnableUnwrapComparatorForComparableRunnable() {\n        return (Comparator<Runnable>) INSTANCE;\n    }\n\n    /**\n     * check the {@code Comparator<Runnable>} is a wrapper {@code TtlRunnableUnwrapComparator} or not.\n     *\n     * @see #getTtlRunnableUnwrapComparator(Comparator)\n     * @see #getTtlRunnableUnwrapComparatorForComparableRunnable()\n     * @since 2.12.3\n     */\n    public static boolean isTtlRunnableUnwrapComparator(@Nullable Comparator<Runnable> comparator) {\n        return comparator instanceof TtlUnwrapComparator;\n    }\n\n    /**\n     * Unwrap {@code TtlRunnableUnwrapComparator} to the original/underneath {@code Comparator<Runnable>}.\n     *\n     * @see #getTtlRunnableUnwrapComparator(Comparator)\n     * @see #getTtlRunnableUnwrapComparatorForComparableRunnable()\n     * @see #isTtlRunnableUnwrapComparator(Comparator)\n     * @see com.alibaba.ttl.TtlUnwrap#unwrap(Object)\n     * @since 2.12.3\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static Comparator<Runnable> unwrap(@Nullable Comparator<Runnable> comparator) {\n        if (!isTtlRunnableUnwrapComparator(comparator)) return comparator;\n\n        return ((TtlUnwrapComparator<Runnable>) comparator).unwrap();\n    }\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlExecutors() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/TtlForkJoinPoolHelper.java",
    "content": "package com.alibaba.ttl.threadpool;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;\nimport java.util.concurrent.ThreadFactory;\n\n/**\n * Util methods to wrap/check/unwrap methods for disable Inheritable wrapper of {@link ForkJoinWorkerThreadFactory}.\n * <p>\n * <b><i>Note:</i></b>\n * <p>\n * all method is {@code null}-safe.\n * for wrap/unwrap methods when input parameter is {@code null}, return {@code null}.\n * for check methods when input parameter is {@code null}, return {@code false}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see ForkJoinPool\n * @see ForkJoinWorkerThreadFactory\n * @see ForkJoinPool#defaultForkJoinWorkerThreadFactory\n * @see java.util.stream.Stream\n * @see TtlExecutors\n * @since 2.10.1\n */\npublic final class TtlForkJoinPoolHelper {\n    /**\n     * Wrapper of {@link ForkJoinWorkerThreadFactory}, disable inheritable.\n     *\n     * @param threadFactory input thread factory\n     * @see DisableInheritableForkJoinWorkerThreadFactory\n     * @see TtlExecutors#getDisableInheritableThreadFactory(ThreadFactory)\n     * @since 2.10.1\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ForkJoinWorkerThreadFactory getDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) {\n        if (threadFactory == null || isDisableInheritableForkJoinWorkerThreadFactory(threadFactory))\n            return threadFactory;\n\n        return new DisableInheritableForkJoinWorkerThreadFactoryWrapper(threadFactory);\n    }\n\n    /**\n     * Wrapper of {@link ForkJoinPool#defaultForkJoinWorkerThreadFactory}, disable inheritable.\n     *\n     * @see #getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory)\n     * @see TtlExecutors#getDefaultDisableInheritableThreadFactory()\n     * @since 2.10.1\n     */\n    @NonNull\n    public static ForkJoinWorkerThreadFactory getDefaultDisableInheritableForkJoinWorkerThreadFactory() {\n        return getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinPool.defaultForkJoinWorkerThreadFactory);\n    }\n\n    /**\n     * check the {@link ForkJoinWorkerThreadFactory} is {@link DisableInheritableForkJoinWorkerThreadFactory} or not.\n     *\n     * @see #getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory)\n     * @see #getDefaultDisableInheritableForkJoinWorkerThreadFactory()\n     * @see DisableInheritableForkJoinWorkerThreadFactory\n     * @since 2.10.1\n     */\n    public static boolean isDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) {\n        return threadFactory instanceof DisableInheritableForkJoinWorkerThreadFactory;\n    }\n\n    /**\n     * Unwrap {@link DisableInheritableForkJoinWorkerThreadFactory} to the original/underneath one.\n     *\n     * @see com.alibaba.ttl.TtlUnwrap#unwrap(Object)\n     * @see DisableInheritableForkJoinWorkerThreadFactory\n     * @see TtlExecutors#unwrap(ThreadFactory)\n     * @since 2.10.1\n     */\n    @Nullable\n    @Contract(value = \"null -> null; !null -> !null\", pure = true)\n    public static ForkJoinWorkerThreadFactory unwrap(@Nullable ForkJoinWorkerThreadFactory threadFactory) {\n        if (!isDisableInheritableForkJoinWorkerThreadFactory(threadFactory)) return threadFactory;\n\n        return ((DisableInheritableForkJoinWorkerThreadFactory) threadFactory).unwrap();\n    }\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlForkJoinPoolHelper() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/TtlUnwrapComparator.java",
    "content": "package com.alibaba.ttl.threadpool;\n\nimport com.alibaba.ttl.TtlUnwrap;\nimport com.alibaba.ttl.spi.TtlWrapper;\nimport edu.umd.cs.findbugs.annotations.NonNull;\n\nimport java.util.Comparator;\n\n/**\n * @see TtlExecutors#getTtlRunnableUnwrapComparator(Comparator)\n * @see TtlExecutors#isTtlRunnableUnwrapComparator(Comparator)\n * @see TtlExecutors#unwrap(Comparator)\n * @since 2.12.3\n */\nfinal class TtlUnwrapComparator<T> implements Comparator<T>, TtlWrapper<Comparator<T>> {\n    private final Comparator<T> comparator;\n\n    public TtlUnwrapComparator(@NonNull Comparator<T> comparator) {\n        this.comparator = comparator;\n    }\n\n    @Override\n    public int compare(T o1, T o2) {\n        return comparator.compare(TtlUnwrap.unwrap(o1), TtlUnwrap.unwrap(o2));\n    }\n\n    @NonNull\n    @Override\n    public Comparator<T> unwrap() {\n        return comparator;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        TtlUnwrapComparator<?> that = (TtlUnwrapComparator<?>) o;\n\n        return comparator.equals(that.comparator);\n    }\n\n    @Override\n    public int hashCode() {\n        return comparator.hashCode();\n    }\n\n    @Override\n    public String toString() {\n        return \"TtlUnwrapComparator{comparator=\" + comparator + '}';\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgent.java",
    "content": "package com.alibaba.ttl.threadpool.agent;\n\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl.threadpool.agent.transformlet.internal.ForkJoinTtlTransformlet;\nimport com.alibaba.ttl.threadpool.agent.transformlet.internal.JdkExecutorTtlTransformlet;\nimport com.alibaba.ttl.threadpool.agent.transformlet.internal.TimerTaskTtlTransformlet;\nimport com.alibaba.ttl.threadpool.agent.transformlet.internal.PriorityBlockingQueueTtlTransformlet;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.lang.instrument.ClassFileTransformer;\nimport java.lang.instrument.Instrumentation;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * TTL Java Agent.\n *\n * <h2>The configuration for TTL agent</h2>\n * <p>\n * Configure TTL agent via {@code -D property}({@link System#getProperties()}) or TTL agent arguments.\n * <ol>\n *     <li>{@code -D property} config format is: {@code -Dkey1=v2 -Dkey2=v2}</li>\n *     <li>TTL agent arguments config format is {@code key1:v1,key2:v2}.<br>\n *         separate key-value pairs by {@code char ,}, and separate key-value by {@code char :}.<br></li>\n * </ol>\n * <B><I>NOTE about the config sources and the precedence:</I></B><br>\n * <ol>\n * <li>Read {@code -D property}({@link System#getProperties()}) first.</li>\n * <li>if no {@code -D property} configured(including empty property value configured by {@code -Dkey1}/{@code -Dkey1=}), read TTL Agent argument configuration.</li>\n * </ol>\n * Below is available TTL agent configuration keys.\n *\n * <h3>Configuration key: Log Type</h3>\n * <p>\n * The log type of TTL Java Agent is configured by key {@code ttl.agent.logger}. Since version {@code 2.6.0}.\n *\n * <ul>\n * <li>{@code ttl.agent.logger : STDERR}<br>\n * only log to {@code stderr} when error.\n * This is <b>default</b>, when no/unrecognized configuration for key {@code ttl.agent.logger}.</li>\n * <li>{@code ttl.agent.logger : STDOUT}<br>\n * Log to {@code stdout}, more info than {@code ttl.agent.logger:STDERR}; This is needed when developing.</li>\n * </ul>\n * <p>\n * Configuration example:\n *\n * <ol>\n * <li>{@code -Dttl.agent.logger=STDOUT}</li>\n * <li>{@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT}</li>\n * </ol>\n *\n * <h3>Configuration key: Disable inheritable for thread pool</h3>\n * <p>\n * Enable \"disable inheritable\" for thread pool, configured by key {@code ttl.agent.disable.inheritable.for.thread.pool}.\n * When no configuration for this key, default is {@code false}(aka. do <b>NOT</b> disable inheritable). Since version {@code 2.10.1}.\n *\n * <ul>\n * <li>rewrite the {@link java.util.concurrent.ThreadFactory} constructor parameter\n * of {@link java.util.concurrent.ThreadPoolExecutor}\n * to {@link com.alibaba.ttl.threadpool.DisableInheritableThreadFactory}\n * by util method {@link com.alibaba.ttl.threadpool.TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory) getDisableInheritableThreadFactory}.\n * </li>\n * <li>rewrite the {@link java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory} constructor parameter\n * of {@link java.util.concurrent.ForkJoinPool}\n * to {@link com.alibaba.ttl.threadpool.DisableInheritableForkJoinWorkerThreadFactory}\n * by util method {@link com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory) getDisableInheritableForkJoinWorkerThreadFactory}.\n * </li>\n * </ul>\n * More info about \"disable inheritable\" see {@link com.alibaba.ttl.TransmittableThreadLocal}.\n * <p>\n * Configuration example:\n *\n * <ol>\n * <li>{@code -Dttl.agent.disable.inheritable.for.thread.pool=true}</li>\n * <li>{@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.disable.inheritable.for.thread.pool:true}</li>\n * </ol>\n *\n * <h3>Configuration key: Enable TimerTask class decoration</h3>\n * <p>\n * Enable TimerTask class decoration is configured by key {@code ttl.agent.enable.timer.task}.\n * Since version {@code 2.7.0}.\n * <p>\n * When no configuration for this key, default is {@code true}(aka. <b>enabled</b>).<br>\n * <b><i>Note</i></b>: Since version {@code 2.11.2} the default value is {@code true}(enable TimerTask class decoration);\n * Before version {@code 2.11.1} default value is {@code false}.\n * <p>\n * Configuration example:\n *\n * <ol>\n * <li>{@code -Dttl.agent.enable.timer.task=false}</li>\n * <li>{@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:false}</li>\n * </ol>\n *\n * <h3>Configuration key: logging the transform class received by TTL Agent</h3>\n * <p>\n * Enable logging the transform class received by TTL Agent by key {@code ttl.agent.log.class.transform},\n * default is {@code false}(aka. do <b>NOT</b> logging the transform class received by TTL Agent).\n * Since version {@code 3.0.0}.\n * <p>\n * Configuration example:\n *\n * <ol>\n * <li>{@code -Dttl.agent.log.class.transform=true}</li>\n * <li>{@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.log.class.transform:true}</li>\n * </ol>\n *\n * <h3>Multi key configuration example</h3>\n * <p>\n * For {@code -D property} config, simply specify multiply {@code -D property}, example:<br>\n * {@code -Dttl.agent.logger=STDOUT -Dttl.agent.disable.inheritable.for.thread.pool=true}\n * <p>\n * For TTL agent arguments config, example:<br>\n * {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT,ttl.agent.disable.inheritable.for.thread.pool:true}\n *\n * <h2>About boot classpath for TTL agent</h2>\n * <p>\n * <b><i>NOTE:</i></b> Since {@code v2.6.0}, TTL agent jar will auto add self to {@code boot classpath}.<br>\n * But you <b>should <i>NOT</i></b> modify the downloaded TTL jar file name in the maven repo(eg: {@code transmittable-thread-local-2.x.y.jar}).<br>\n * if you modified the downloaded TTL agent jar file name(eg: {@code ttl-foo-name-changed.jar}),\n * you must add TTL agent jar to {@code boot classpath} manually\n * by java option {@code -Xbootclasspath/a:path/to/ttl-foo-name-changed.jar}.\n * <p>\n * The implementation of auto adding self agent jar to {@code boot classpath} use\n * the {@code Boot-Class-Path} property of manifest file({@code META-INF/MANIFEST.MF}) in the TTL Java Agent Jar:\n *\n * <blockquote>\n * <dl>\n * <dt>Boot-Class-Path</dt>\n * <dd>\n * A list of paths to be searched by the bootstrap class loader. Paths represent directories or libraries (commonly referred to as JAR or zip libraries on many platforms).\n * These paths are searched by the bootstrap class loader after the platform specific mechanisms of locating a class have failed. Paths are searched in the order listed.\n * </dd>\n * </dl>\n * </blockquote>\n * <p>\n * More info about {@code Boot-Class-Path} see\n * <a href=\"https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html\">The mechanism for instrumentation</a>.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see Instrumentation\n * @see <a href=\"https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html\">The mechanism for instrumentation</a>\n * @see <a href=\"https://docs.oracle.com/en/java/javase/21/docs/specs/jar/jar.html#jar-manifest\">JAR File Specification - JAR Manifest</a>\n * @see <a href=\"https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html\">Working with Manifest Files - The Java™ Tutorials</a>\n * @see com.alibaba.ttl.TransmittableThreadLocal\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ScheduledThreadPoolExecutor\n * @see java.util.concurrent.ForkJoinPool\n * @see java.util.TimerTask\n * @since 0.9.0\n */\npublic final class TtlAgent {\n\n    /**\n     * the TTL agent configuration key: Log Type\n     *\n     * @see TtlAgent\n     * @since 3.0.0\n     */\n    public static final String TTL_AGENT_LOGGER_KEY = \"ttl.agent.logger\";\n\n    /**\n     * the TTL agent configuration key: Disable inheritable for thread pool\n     *\n     * @see TtlAgent\n     * @since 3.0.0\n     */\n    public static final String TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY = \"ttl.agent.disable.inheritable.for.thread.pool\";\n\n    /**\n     * the TTL agent configuration key: Enable TimerTask class decoration\n     *\n     * @see TtlAgent\n     * @since 3.0.0\n     */\n    public static final String TTL_AGENT_ENABLE_TIMER_TASK_KEY = \"ttl.agent.enable.timer.task\";\n\n    /**\n     * the TTL agent configuration key: logging the transform class received by TTL Agent\n     *\n     * @see TtlAgent\n     * @since 3.0.0\n     */\n    public static final String TTL_AGENT_LOG_CLASS_TRANSFORM_KEY = \"ttl.agent.log.class.transform\";\n\n\n    // ======== TTL Agent internal States ========\n\n    private static volatile Map<String, String> kvs;\n\n    private static volatile boolean ttlAgentLoaded = false;\n\n    /**\n     * Entrance method of TTL Java Agent.\n     *\n     * @see TtlAgent\n     */\n    public static void premain(final String agentArgs, @NonNull final Instrumentation inst) {\n        kvs = TtlAgentHelper.splitCommaColonStringToKV(agentArgs);\n\n        Logger.setLoggerImplType(getLoggerType());\n        final Logger logger = Logger.getLogger(TtlAgent.class);\n\n        try {\n            logger.info(\"[TtlAgent.premain] begin, agentArgs: \" + agentArgs + \", Instrumentation: \" + inst);\n\n            logger.info(logTtlAgentConfig());\n\n            final List<TtlTransformlet> transformletList = new ArrayList<>();\n\n            transformletList.add(new JdkExecutorTtlTransformlet());\n            transformletList.add(new PriorityBlockingQueueTtlTransformlet());\n\n            transformletList.add(new ForkJoinTtlTransformlet());\n\n            if (isEnableTimerTask()) transformletList.add(new TimerTaskTtlTransformlet());\n\n            final ClassFileTransformer transformer = new TtlTransformer(transformletList, isLogClassTransform());\n            inst.addTransformer(transformer, true);\n            logger.info(\"[TtlAgent.premain] add Transformer \" + transformer.getClass().getName() + \" success\");\n\n            logger.info(\"[TtlAgent.premain] end\");\n\n            ttlAgentLoaded = true;\n        } catch (Exception e) {\n            String msg = \"Fail to load TtlAgent , cause: \" + e.toString();\n            logger.error(msg, e);\n            throw new IllegalStateException(msg, e);\n        }\n    }\n\n    private static String logTtlAgentConfig() {\n        return \"TTL Agent configurations:\"\n            + \"\\n    \" + TTL_AGENT_LOGGER_KEY + \"=\" + getLoggerType()\n            + \"\\n    \" + TTL_AGENT_LOG_CLASS_TRANSFORM_KEY + \"=\" + isLogClassTransform()\n            + \"\\n    \" + TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY + \"=\" + isDisableInheritableForThreadPool()\n            + \"\\n    \" + TTL_AGENT_ENABLE_TIMER_TASK_KEY + \"=\" + isEnableTimerTask();\n    }\n\n    /**\n     * Whether TTL agent is loaded.\n     *\n     * @since 2.9.0\n     */\n    public static boolean isTtlAgentLoaded() {\n        return ttlAgentLoaded;\n    }\n\n    /**\n     * Whether disable inheritable for thread pool is enhanced by ttl agent, check {@link #isTtlAgentLoaded()} first.\n     * <p>\n     * Same as {@code isBooleanOptionSet(TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY)}.\n     *\n     * @see com.alibaba.ttl.threadpool.TtlExecutors#getDefaultDisableInheritableThreadFactory()\n     * @see com.alibaba.ttl.threadpool.TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)\n     * @see com.alibaba.ttl.threadpool.DisableInheritableThreadFactory\n     * @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper#getDefaultDisableInheritableForkJoinWorkerThreadFactory()\n     * @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory)\n     * @see com.alibaba.ttl.threadpool.DisableInheritableForkJoinWorkerThreadFactory\n     * @see com.alibaba.ttl.TransmittableThreadLocal\n     * @see TtlAgent\n     * @see #isBooleanOptionSet(String)\n     * @see #TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY\n     * @since 2.10.1\n     */\n    public static boolean isDisableInheritableForThreadPool() {\n        return isBooleanOptionSet(TTL_AGENT_DISABLE_INHERITABLE_FOR_THREAD_POOL_KEY);\n    }\n\n    /**\n     * Whether timer task is enhanced by ttl agent, check {@link #isTtlAgentLoaded()} first.\n     * <p>\n     * Same as {@code isBooleanOptionSet(TTL_AGENT_ENABLE_TIMER_TASK_KEY, true)}.\n     *\n     * @see java.util.Timer\n     * @see java.util.TimerTask\n     * @see TtlAgent\n     * @see #isBooleanOptionSet(String, boolean)\n     * @see #TTL_AGENT_ENABLE_TIMER_TASK_KEY\n     * @since 2.10.1\n     */\n    public static boolean isEnableTimerTask() {\n        return isBooleanOptionSet(TTL_AGENT_ENABLE_TIMER_TASK_KEY, true);\n    }\n\n    /**\n     * Whether logging the transform class received by {@link TtlAgent}.\n     * <p>\n     * Same as {@code isBooleanOptionSet(TTL_AGENT_LOG_CLASS_TRANSFORM_KEY)}.\n     *\n     * @see TtlAgent\n     * @see #isBooleanOptionSet(String)\n     * @see #TTL_AGENT_LOG_CLASS_TRANSFORM_KEY\n     * @since 3.0.0\n     */\n    public static boolean isLogClassTransform() {\n        return isBooleanOptionSet(TTL_AGENT_LOG_CLASS_TRANSFORM_KEY);\n    }\n\n    /**\n     * Get the TTL Agent Log type.\n     * <p>\n     * Same as {@code getStringOptionValue(TTL_AGENT_LOGGER_KEY, Logger.STDERR)}.\n     *\n     * @see Logger\n     * @see Logger#STDERR\n     * @see Logger#STDOUT\n     * @see TtlAgent\n     * @see #getStringOptionValue(String, String)\n     * @see #TTL_AGENT_LOGGER_KEY\n     * @since 3.0.0\n     */\n    @NonNull\n    public static String getLoggerType() {\n        return getStringOptionValue(TTL_AGENT_LOGGER_KEY, Logger.STDERR);\n    }\n\n    // ======== Generic Option Getters ========\n\n    /**\n     * Generic Option Getters for {@code boolean type} option.\n     * <p>\n     * Same as {@code isBooleanOptionSet(key, false)}.\n     *\n     * @see #isBooleanOptionSet(String, boolean)\n     * @see TtlAgent\n     * @since 3.0.0\n     */\n    public static boolean isBooleanOptionSet(@NonNull String key) {\n        return isBooleanOptionSet(key, false);\n    }\n\n    /**\n     * Generic Option Getters for {@code boolean type} option.\n     *\n     * @see TtlAgent\n     * @since 3.0.0\n     */\n    public static boolean isBooleanOptionSet(@NonNull String key, boolean defaultValueIfKeyAbsent) {\n        return TtlAgentHelper.isBooleanOptionSet(kvs, key, defaultValueIfKeyAbsent);\n    }\n\n    /**\n     * Generic Option Getters for {@code string type} option.\n     * <p>\n     * usage example:\n     * <p>\n     * if {@code -Dttl.agent.logger=STDOUT} or\n     * TTL Agent configuration is {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.logger:STDOUT},\n     * {@code getOptionValue(\"ttl.agent.logger\")} return {@code STDOUT}.\n     *\n     * @see TtlAgent\n     * @since 3.0.0\n     */\n    @NonNull\n    public static String getStringOptionValue(@NonNull String key, @NonNull String defaultValue) {\n        return TtlAgentHelper.getStringOptionValue(kvs, key, defaultValue);\n    }\n\n    /**\n     * Generic Option Getters for {@code string list type} option.\n     * <p>\n     * TTL configuration use {@code |} to separate items.\n     * <p>\n     * usage example:<br>\n     * if {@code -Dfoo.list=v1|v2|v3} or\n     * TTL Agent configuration is {@code -javaagent:/path/to/transmittable-thread-local-2.x.y.jar=foo.list:v1|v2|v3},\n     * {@code getOptionValue(\"foo.list\")} return {@code [v1, v2, v3]}.\n     *\n     * @see TtlAgent\n     */\n    @NonNull\n    static List<String> getOptionStringListValues(@NonNull String key) {\n        return TtlAgentHelper.getOptionStringListValues(kvs, key);\n    }\n\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlAgent() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgentHelper.java",
    "content": "package com.alibaba.ttl.threadpool.agent;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.util.*;\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 3.0.0\n */\nfinal class TtlAgentHelper {\n\n    // ======== Option Getter Methods ========\n\n    static boolean isBooleanOptionSet(\n        @Nullable final Map<String, String> kvs, @NonNull String key,\n        boolean defaultValueIfKeyAbsent\n    ) {\n        return isBooleanOptionSet(kvs, key, defaultValueIfKeyAbsent, true);\n    }\n\n    static boolean isBooleanOptionSet(\n        @Nullable final Map<String, String> kvs, @NonNull String key,\n        boolean defaultValueIfKeyAbsent, boolean defaultValueIfValueAbsent\n    ) {\n        final String value;\n\n        final Properties properties = System.getProperties();\n        if (properties.containsKey(key)) {\n            value = properties.getProperty(key).trim();\n        } else {\n            if (kvs == null) return defaultValueIfKeyAbsent;\n\n            final boolean containsKey = kvs.containsKey(key);\n            if (!containsKey) return defaultValueIfKeyAbsent;\n\n            value = kvs.get(key).trim();\n        }\n\n        // if value is blank\n        if (value.isEmpty()) return defaultValueIfValueAbsent;\n\n        return !\"false\".equalsIgnoreCase(value);\n    }\n\n    @NonNull\n    static String getStringOptionValue(\n        @Nullable final Map<String, String> kvs, @NonNull String key,\n        @NonNull String defaultValue\n    ) {\n        final String value;\n\n        final Properties properties = System.getProperties();\n        if (properties.containsKey(key)) {\n            value = properties.getProperty(key).trim();\n        } else {\n            if (kvs == null) return defaultValue;\n\n            final boolean containsKey = kvs.containsKey(key);\n            if (!containsKey) return defaultValue;\n\n            value = kvs.get(key).trim();\n        }\n\n        // if value is blank\n        if (value.isEmpty()) return defaultValue;\n\n        return value;\n    }\n\n    @NonNull\n    @SuppressWarnings(\"unchecked\")\n    static List<String> getOptionStringListValues(@Nullable final Map<String, String> kvs, @NonNull String key) {\n        final String value;\n\n        final Properties properties = System.getProperties();\n        if (properties.containsKey(key)) {\n            value = properties.getProperty(key);\n        } else {\n            if (kvs == null) return Collections.EMPTY_LIST;\n\n            value = kvs.get(key);\n        }\n\n        return splitListStringToStringList(value);\n    }\n\n    // ======== Simple Parse Util Methods ========\n\n    /**\n     * Split {@code json} like String({@code \"k1:v1,k2:v2\"}) to KV map({@code \"k1\"->\"v1\", \"k2\"->\"v2\"}).\n     */\n    @NonNull\n    static Map<String, String> splitCommaColonStringToKV(@Nullable final String commaColonString) {\n        final Map<String, String> ret = new HashMap<>();\n        if (commaColonString == null || commaColonString.trim().length() == 0) return ret;\n\n        final String[] splitKvArray = commaColonString.trim().split(\"\\\\s*,\\\\s*\");\n        for (String kvString : splitKvArray) {\n            final String[] kv = kvString.trim().split(\"\\\\s*:\\\\s*\");\n            if (kv.length == 0) continue;\n\n            if (kv.length == 1) ret.put(kv[0], \"\");\n            else ret.put(kv[0], kv[1]);\n        }\n\n        return ret;\n    }\n\n    /**\n     * Split String {@code \"v1|v2|v3\"} to String List({@code [v1, v2, v3]}).\n     */\n    @NonNull\n    static List<String> splitListStringToStringList(@Nullable String listString) {\n        final List<String> ret = new ArrayList<>();\n        if (listString == null || listString.trim().length() == 0) return ret;\n\n        final String[] split = listString.trim().split(\"\\\\s*\\\\|\\\\s*\");\n        for (String s : split) {\n            if (s.length() == 0) continue;\n\n            ret.add(s);\n        }\n\n        return ret;\n    }\n\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlAgentHelper() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/TtlExtensionTransformletManager.java",
    "content": "package com.alibaba.ttl.threadpool.agent;\n\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport javassist.CannotCompileException;\nimport javassist.NotFoundException;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.lang.reflect.InvocationTargetException;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\n\nimport static com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.getLocationUrlOfClass;\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 3.0.0\n */\nfinal class TtlExtensionTransformletManager {\n    private static final Logger logger = Logger.getLogger(TtlExtensionTransformletManager.class);\n\n    private static final String TTL_AGENT_EXTENSION_TRANSFORMLET_FILE = \"META-INF/ttl.agent.transformlets\";\n\n    public TtlExtensionTransformletManager() {\n    }\n\n    public String extensionTransformletDoTransform(@NonNull final ClassInfo classInfo) throws NotFoundException, CannotCompileException, IOException {\n        final Map<String, TtlTransformlet> transformlets = classLoader2ExtensionTransformletsIncludeParentCL.get(classInfo.getClassLoader());\n        if (transformlets == null) return null;\n\n        for (Map.Entry<String, TtlTransformlet> entry : transformlets.entrySet()) {\n            final String className = entry.getKey();\n            final TtlTransformlet transformlet = entry.getValue();\n\n            transformlet.doTransform(classInfo);\n            if (classInfo.isModified()) {\n                return className;\n            }\n        }\n\n        return null;\n    }\n\n    // NOTE: use WeakHashMap as a Set collection, value is always null.\n    private final WeakHashMap<ClassLoader, ?> collectedClassLoaderHistory = new WeakHashMap<>(512);\n\n    // Map: ExtensionTransformlet ClassLoader -> ExtensionTransformlet ClassName -> ExtensionTransformlet instance(not include from parent classloader)\n    private final WeakHashMap<ClassLoader, Map<String, TtlTransformlet>> classLoader2ExtensionTransformlets =\n            new WeakHashMap<>(512);\n\n    // Map: ExtensionTransformlet ClassLoader -> ExtensionTransformlet ClassName -> ExtensionTransformlet instance(include from parent classloader)\n    private final WeakHashMap<ClassLoader, Map<String, TtlTransformlet>> classLoader2ExtensionTransformletsIncludeParentCL =\n            new WeakHashMap<>(512);\n\n    public void collectExtensionTransformlet(@NonNull final ClassInfo classInfo) throws IOException {\n        final ClassLoader classLoader = classInfo.getClassLoader();\n        // classloader may null be if the bootstrap loader,\n        // which classloader must contains NO Ttl Agent Extension Transformlet, so just safe skip\n        if (classLoader == null) return;\n\n        // this classLoader is collected, so skip collection\n        if (collectedClassLoaderHistory.containsKey(classLoader)) return;\n        collectedClassLoaderHistory.put(classLoader, null);\n\n        logger.info(\"[TtlExtensionTransformletCollector] collecting TTL Extension Transformlets from classloader \" + classLoader);\n\n        final LinkedHashSet<String> extensionTransformletClassNames = readExtensionTransformletClassNames(classLoader);\n\n        final String foundMsgHead = \"[TtlExtensionTransformletCollector] found TTL Extension Transformlet class \";\n        final String failLoadMsgHead = \"[TtlExtensionTransformletCollector] fail to load TTL Extension Transformlet \";\n        final Map<ClassLoader, Set<TtlTransformlet>> loadedTransformlet =\n            loadExtensionInstances(classLoader, extensionTransformletClassNames, TtlTransformlet.class, foundMsgHead, failLoadMsgHead);\n\n        mergeToClassLoader2ExtensionTransformlet(classLoader2ExtensionTransformlets, loadedTransformlet);\n\n        updateClassLoader2ExtensionTransformletsIncludeParentCL(\n            classLoader2ExtensionTransformlets, classLoader2ExtensionTransformletsIncludeParentCL);\n    }\n\n    // extension transformlet configuration file URL location string -> URL contained extension transformlet class names\n    private final Map<String, LinkedHashSet<String>> redExtensionTransformletFileHistory = new HashMap<>();\n\n    private LinkedHashSet<String> readExtensionTransformletClassNames(ClassLoader classLoader) throws IOException {\n        final Enumeration<URL> extensionFiles = classLoader.getResources(TTL_AGENT_EXTENSION_TRANSFORMLET_FILE);\n\n        final Pair<LinkedHashSet<String>, Set<String>> pair = readLinesFromExtensionFiles(extensionFiles, redExtensionTransformletFileHistory);\n        final LinkedHashSet<String> extensionTransformletClassNames = pair.first;\n        final Set<String> stringUrls = pair.second;\n        if (!stringUrls.isEmpty())\n            logger.info(\"[TtlExtensionTransformletCollector] found TTL Extension Transformlet configuration files from classloader \"\n                + classLoader + \" : \" + stringUrls);\n\n        return extensionTransformletClassNames;\n    }\n\n    private static void mergeToClassLoader2ExtensionTransformlet(\n        Map<ClassLoader, Map<String, TtlTransformlet>> destination, Map<ClassLoader, Set<TtlTransformlet>> loadedTransformlets\n    ) {\n        for (Map.Entry<ClassLoader, Set<TtlTransformlet>> entry : loadedTransformlets.entrySet()) {\n            final ClassLoader classLoader = entry.getKey();\n            final Set<TtlTransformlet> transformlets = entry.getValue();\n\n            Map<String, TtlTransformlet> className2Transformlets = destination.computeIfAbsent(classLoader, k -> new HashMap<>());\n\n            for (TtlTransformlet t : transformlets) {\n                final String className = t.getClass().getName();\n                if (className2Transformlets.containsKey(className)) continue;\n\n                className2Transformlets.put(className, t);\n                logger.info(\"[TtlExtensionTransformletCollector] add TTL Extension Transformlet \" + className + \" success\");\n            }\n        }\n    }\n\n    static void updateClassLoader2ExtensionTransformletsIncludeParentCL(\n        Map<ClassLoader, Map<String, TtlTransformlet>> classLoader2ExtensionTransformlets,\n        Map<ClassLoader, Map<String, TtlTransformlet>> classLoader2ExtensionTransformletsIncludeParentCL\n    ) {\n        for (Map.Entry<ClassLoader, Map<String, TtlTransformlet>> entry : classLoader2ExtensionTransformlets.entrySet()) {\n            final ClassLoader classLoader = entry.getKey();\n            final Map<String, TtlTransformlet> merged = childClassLoaderFirstMergeTransformlets(classLoader2ExtensionTransformlets, classLoader);\n            classLoader2ExtensionTransformletsIncludeParentCL.put(classLoader, merged);\n        }\n    }\n\n    static Map<String, TtlTransformlet> childClassLoaderFirstMergeTransformlets(\n        Map<ClassLoader, Map<String, TtlTransformlet>> classLoader2Transformlet, ClassLoader classLoader\n    ) {\n        Map<String, TtlTransformlet> ret = new HashMap<>();\n\n        final ArrayDeque<ClassLoader> chain = new ArrayDeque<>();\n        chain.add(classLoader);\n        while (classLoader.getParent() != null) {\n            classLoader = classLoader.getParent();\n\n            chain.addFirst(classLoader);\n        }\n\n        for (ClassLoader loader : chain) {\n            final Map<String, TtlTransformlet> m = classLoader2Transformlet.get(loader);\n            if (m == null) continue;\n\n            ret.putAll(m);\n        }\n\n        return ret;\n    }\n\n    // ======== Extension load util methods ========\n\n    static <T> Map<ClassLoader, Set<T>> loadExtensionInstances(\n        ClassLoader classLoader, LinkedHashSet<String> instanceClassNames, Class<T> superType,\n        String foundMsgHead, String failLoadMsgHead\n    ) {\n        Map<ClassLoader, Set<T>> ret = new HashMap<>();\n\n        for (final String className : instanceClassNames) {\n            try {\n                final Class<?> clazz = classLoader.loadClass(className);\n                if (!superType.isAssignableFrom(clazz)) {\n                    final String msg = foundMsgHead + className\n                        + \" from classloader \" + classLoader\n                        + \" at location \" + getLocationUrlOfClass(clazz)\n                        + \", but NOT subtype of \" + superType.getName() + \", ignored!\";\n                    logger.error(msg);\n                    continue;\n                }\n\n                Object instance = clazz.getDeclaredConstructor().newInstance();\n\n                final ClassLoader actualClassLoader = instance.getClass().getClassLoader();\n                Set<T> set = ret.computeIfAbsent(actualClassLoader, k -> new HashSet<>());\n                set.add(superType.cast(instance));\n\n                final String msg = foundMsgHead + className\n                    + \", and loaded from classloader \" + classLoader\n                    + \" at location \" + getLocationUrlOfClass(clazz);\n                logger.info(msg);\n            } catch (ClassNotFoundException e) {\n                final String msg = failLoadMsgHead + className + \" from classloader \" + classLoader + \", cause: \" + e.toString();\n                logger.warn(msg, e);\n            } catch (IllegalAccessException | InstantiationException | NoSuchMethodException |\n                     InvocationTargetException e) {\n                final String msg = failLoadMsgHead + className + \" from classloader \" + classLoader + \", cause: \" + e.toString();\n                logger.error(msg, e);\n            }\n        }\n\n        return ret;\n    }\n\n    // return: read lines from URL, url strings\n    @NonNull\n    static Pair<LinkedHashSet<String>, Set<String>> readLinesFromExtensionFiles(\n        /* input */ @NonNull Enumeration<URL> extensionFiles,\n        /* input/output, map url string -> content lines */ @NonNull Map<String, LinkedHashSet<String>> redExtensionFilesHistory\n    ) {\n        final LinkedHashSet<String> mergedLines = new LinkedHashSet<>();\n        final Set<String> stringUrls = new HashSet<>();\n\n        while (extensionFiles.hasMoreElements()) {\n            final URL url = extensionFiles.nextElement();\n\n            final String urlString = url.toString();\n            stringUrls.add(urlString);\n\n            LinkedHashSet<String> lines;\n            if (redExtensionFilesHistory.containsKey(urlString)) {\n                lines = redExtensionFilesHistory.get(urlString);\n            } else {\n                lines = readLines(url);\n\n                redExtensionFilesHistory.put(urlString, lines);\n            }\n\n            mergedLines.addAll(lines);\n        }\n\n        return new Pair<>(mergedLines, stringUrls);\n    }\n\n    /**\n     * this method is modified based on {@link java.util.ServiceLoader}\n     */\n    @SuppressWarnings(\"StatementWithEmptyBody\")\n    static LinkedHashSet<String> readLines(URL extensionFile) {\n        InputStream inputStream = null;\n        BufferedReader reader = null;\n\n        LinkedHashSet<String> names = new LinkedHashSet<>();\n        try {\n            inputStream = extensionFile.openStream();\n            reader = new BufferedReader(new InputStreamReader(inputStream, UTF_8));\n            int lineNum = 1;\n            while ((lineNum = parseLine(extensionFile, reader, lineNum, names)) >= 0) ;\n        } catch (IOException x) {\n            logger.error(\"Error reading configuration file \" + extensionFile, x);\n        } finally {\n            try {\n                if (reader != null) reader.close();\n                if (inputStream != null) inputStream.close();\n            } catch (IOException y) {\n                logger.warn(\"Error closing configuration file \" + extensionFile, y);\n            }\n        }\n\n        return names;\n    }\n\n\n    /**\n     * this method is modified based on {@link java.util.ServiceLoader}\n     */\n    private static int parseLine(URL url, BufferedReader reader, int lineNum, LinkedHashSet<String> names) throws IOException {\n        String line = reader.readLine();\n        if (line == null) {\n            return -1;\n        }\n\n        // remove comments that start with `#`\n        int ci = line.indexOf('#');\n        if (ci >= 0) line = line.substring(0, ci);\n\n        line = line.trim();\n\n        int n = line.length();\n        if (n != 0) {\n            if ((line.indexOf(' ') >= 0) || (line.indexOf('\\t') >= 0)) {\n                logger.error(\"Illegal syntax \" + line + \"in configuration file\" + url + \", contains space or tab; ignore this line!\");\n                return lineNum + 1;\n            }\n\n            int cp = line.codePointAt(0);\n            if (!Character.isJavaIdentifierStart(cp)) {\n                logger.error(\"Illegal extension class name \" + line + \" in configuration file \" + url + \"; ignore this line!\");\n                return lineNum + 1;\n            }\n            for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {\n                cp = line.codePointAt(i);\n                if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) {\n                    logger.error(\"Illegal extension class name: \" + line + \" in configuration file \" + url + \"; ignore this line!\");\n                    return lineNum + 1;\n                }\n            }\n\n            names.add(line);\n        }\n\n        return lineNum + 1;\n    }\n\n    static class Pair<T, U> {\n        T first;\n        U second;\n\n        public Pair(T first, U second) {\n            this.first = first;\n            this.second = second;\n        }\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/TtlTransformer.java",
    "content": "package com.alibaba.ttl.threadpool.agent;\n\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\n\nimport java.lang.instrument.ClassFileTransformer;\nimport java.security.ProtectionDomain;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.isClassUnderPackage;\n\n/**\n * TTL {@link ClassFileTransformer} of Java Agent\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see ClassFileTransformer\n * @see <a href=\"https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html\">The mechanism for instrumentation</a>\n * @since 0.9.0\n */\npublic class TtlTransformer implements ClassFileTransformer {\n    private static final Logger logger = Logger.getLogger(TtlTransformer.class);\n\n    /**\n     * \"<code>null</code> if no transform is performed\",\n     * see {@code @return} of {@link ClassFileTransformer#transform(ClassLoader, String, Class, ProtectionDomain, byte[])}\n     */\n    @SuppressFBWarnings({\"EI_EXPOSE_REP\"})\n    // [ERROR] com.alibaba.ttl.threadpool.agent.TtlTransformer.transform(ClassLoader, String, Class, ProtectionDomain, byte[])\n    //         may expose internal representation by returning TtlTransformer.NO_TRANSFORM\n    // the value is null, so there is NO \"EI_EXPOSE_REP\" problem actually.\n    private static final byte[] NO_TRANSFORM = null;\n\n    private final TtlExtensionTransformletManager extensionTransformletManager;\n    private final List<TtlTransformlet> transformletList = new ArrayList<>();\n    private final boolean logClassTransform;\n\n    TtlTransformer(List<? extends TtlTransformlet> transformletList, boolean logClassTransform) {\n        extensionTransformletManager = new TtlExtensionTransformletManager();\n\n        this.logClassTransform = logClassTransform;\n        for (TtlTransformlet ttlTransformlet : transformletList) {\n            this.transformletList.add(ttlTransformlet);\n            logger.info(\"[TtlTransformer] add Transformlet \" + ttlTransformlet.getClass().getName());\n        }\n    }\n\n    /**\n     * info about class loader: may be <code>null</code> if the bootstrap loader.\n     * <p>\n     * more info see {@link ClassFileTransformer#transform(java.lang.ClassLoader, java.lang.String, java.lang.Class, java.security.ProtectionDomain, byte[])}\n     */\n    @Override\n    public final byte[] transform(@Nullable final ClassLoader loader, @Nullable final String classFile, final Class<?> classBeingRedefined,\n                                  final ProtectionDomain protectionDomain, @NonNull final byte[] classFileBuffer) {\n        try {\n            // Lambda has no class file, no need to transform, just return.\n            if (classFile == null) return NO_TRANSFORM;\n\n            final ClassInfo classInfo = new ClassInfo(classFile, classFileBuffer, loader);\n            if (isClassUnderPackage(classInfo.getClassName(), \"com.alibaba.ttl\")) return NO_TRANSFORM;\n            if (isClassUnderPackage(classInfo.getClassName(), \"java.lang\")) return NO_TRANSFORM;\n\n            if (logClassTransform)\n                logger.info(\"[TtlTransformer] transforming \" + classInfo.getClassName()\n                        + \" from classloader \" + classInfo.getClassLoader()\n                        + \" at location \" + classInfo.getLocationUrl());\n\n            extensionTransformletManager.collectExtensionTransformlet(classInfo);\n\n            for (TtlTransformlet transformlet : transformletList) {\n                transformlet.doTransform(classInfo);\n                if (classInfo.isModified()) {\n                    logger.info(\"[TtlTransformer] \" + transformlet.getClass().getName() + \" transformed \" + classInfo.getClassName()\n                            + \" from classloader \" + classInfo.getClassLoader()\n                            + \" at location \" + classInfo.getLocationUrl());\n                    return classInfo.getCtClass().toBytecode();\n                }\n            }\n\n            final String transformlet = extensionTransformletManager.extensionTransformletDoTransform(classInfo);\n            if (classInfo.isModified()) {\n                logger.info(\"[TtlTransformer] \" + transformlet + \" transformed \" + classInfo.getClassName()\n                        + \" from classloader \" + classInfo.getClassLoader()\n                        + \" at location \" + classInfo.getLocationUrl());\n                return classInfo.getCtClass().toBytecode();\n            }\n        } catch (Throwable t) {\n            String msg = \"[TtlTransformer] fail to transform class \" + classFile + \", cause: \" + t.toString();\n            logger.error(msg, t);\n            throw new IllegalStateException(msg, t);\n        }\n\n        return NO_TRANSFORM;\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/logging/Logger.java",
    "content": "package com.alibaba.ttl.threadpool.agent.logging;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.logging.Level;\n\n/**\n * Logger adaptor for ttl TTL agent/transformlet. Only use for TTL agent/transformlet!\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet\n * @see com.alibaba.ttl.threadpool.agent.TtlAgent\n * @since 3.0.0\n */\npublic abstract class Logger {\n    public static final String STDOUT = \"STDOUT\";\n    public static final String STDERR = \"STDERR\";\n\n    private static volatile int loggerImplType = -1;\n\n    public static void setLoggerImplType(String type) {\n        if (loggerImplType != -1) {\n            throw new IllegalStateException(\"TTL logger implementation type is already set! type = \" + loggerImplType);\n        }\n\n        if (STDERR.equalsIgnoreCase(type)) loggerImplType = 0;\n        else if (STDOUT.equalsIgnoreCase(type)) loggerImplType = 1;\n        else loggerImplType = 0;\n    }\n\n    /**\n     * Only for test code\n     */\n    public static void setLoggerImplTypeIfNotSetYet(String type) {\n        if (loggerImplType == -1) setLoggerImplType(type);\n    }\n\n    public static Logger getLogger(Class<?> clazz) {\n        if (loggerImplType == -1) throw new IllegalStateException(\"TTL logger implementation type is NOT set!\");\n\n        switch (loggerImplType) {\n            case 1:\n                return new StdOutLogger(clazz);\n            default:\n                return new StdErrorLogger(clazz);\n        }\n    }\n\n    final Class<?> logClass;\n\n    private Logger(Class<?> logClass) {\n        this.logClass = logClass;\n    }\n\n    public void info(String msg) {\n        log(Level.INFO, msg, null);\n    }\n\n    public void warn(String msg) {\n        log(Level.WARNING, msg, null);\n    }\n\n    public void warn(String msg, Throwable thrown) {\n        log(Level.WARNING, msg, thrown);\n    }\n\n    public void error(String msg) {\n        log(Level.SEVERE, msg, null);\n    }\n\n    public void error(String msg, Throwable thrown) {\n        log(Level.SEVERE, msg, thrown);\n    }\n\n    protected abstract void log(Level level, String msg, Throwable thrown);\n\n    private static class StdErrorLogger extends Logger {\n        StdErrorLogger(Class<?> clazz) {\n            super(clazz);\n        }\n\n        @Override\n        public void log(Level level, String msg, Throwable thrown) {\n            if (level == Level.SEVERE) {\n                final String time = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\").format(new Date());\n                System.err.printf(\"%s %s [%s] %s: %s%n\", time, level, Thread.currentThread().getName(), logClass.getSimpleName(), msg);\n                if (thrown != null) thrown.printStackTrace();\n            }\n        }\n    }\n\n    private static class StdOutLogger extends Logger {\n        StdOutLogger(Class<?> clazz) {\n            super(clazz);\n        }\n\n        @Override\n        public void log(Level level, String msg, Throwable thrown) {\n            final String time = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\").format(new Date());\n            System.out.printf(\"%s %s [%s] %s: %s%n\", time, level, Thread.currentThread().getName(), logClass.getSimpleName(), msg);\n            if (thrown != null) thrown.printStackTrace(System.out);\n        }\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/logging/package-info.java",
    "content": "/**\n * TTL Agent Logger. <b>Only</b> use for TTL agent/transformlet.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.threadpool.agent.logging.Logger\n * @since 3.0.0\n */\npackage com.alibaba.ttl.threadpool.agent.logging;\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/package-info.java",
    "content": "/**\n * TTL Agent.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.threadpool.agent.TtlAgent\n * @see <a href=\"https://docs.oracle.com/en/java/javase/21/docs/api/java.instrument/java/lang/instrument/package-summary.html\">The mechanism for instrumentation</a>\n */\npackage com.alibaba.ttl.threadpool.agent;\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/ClassInfo.java",
    "content": "package com.alibaba.ttl.threadpool.agent.transformlet;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport javassist.ClassPool;\nimport javassist.CtClass;\nimport javassist.LoaderClassPath;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.net.URL;\n\nimport static com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.getLocationUrlOfClass;\n\n/**\n * Class Info for {@link TtlTransformlet}.\n *\n * <B><I>Caution:</I></B><br>\n * Do <b>NOT</b> load {@link Class} which is transforming, or the transform will lose effectiveness.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 3.0.0\n */\npublic class ClassInfo {\n    private final String transformerClassFile;\n    private final String className;\n    private final byte[] classFileBuffer;\n    private final ClassLoader loader;\n\n    // SuppressFBWarnings for classFileBuffer/loader parameter:\n    //   [ERROR] new com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo(String, byte[], ClassLoader)\n    //   may expose internal representation by storing an externally mutable object\n    //   into ClassInfo.classFileBuffer/loader\n    public ClassInfo(@NonNull String transformerClassFile,\n                     @NonNull @SuppressFBWarnings({\"EI_EXPOSE_REP2\"}) byte[] classFileBuffer,\n                     @Nullable @SuppressFBWarnings({\"EI_EXPOSE_REP2\"}) ClassLoader loader) {\n        this.transformerClassFile = transformerClassFile;\n        this.className = toClassName(transformerClassFile);\n        this.classFileBuffer = classFileBuffer;\n        this.loader = loader;\n    }\n\n    @NonNull\n    public String getClassName() {\n        return className;\n    }\n\n    private CtClass ctClass;\n\n    public URL getLocationUrl() throws IOException {\n        return getLocationUrlOfClass(getCtClass());\n    }\n\n    @NonNull\n    @SuppressFBWarnings({\"EI_EXPOSE_REP\"})\n    // [ERROR] Medium: com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo.getCtClass()\n    // may expose internal representation\n    // by returning ClassInfo.ctClass [com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo]\n    public CtClass getCtClass() throws IOException {\n        if (ctClass != null) return ctClass;\n\n        final ClassPool classPool = new ClassPool(true);\n        if (loader == null) {\n            classPool.appendClassPath(new LoaderClassPath(ClassLoader.getSystemClassLoader()));\n        } else {\n            classPool.appendClassPath(new LoaderClassPath(loader));\n        }\n\n        final CtClass clazz = classPool.makeClass(new ByteArrayInputStream(classFileBuffer), false);\n        clazz.defrost();\n\n        this.ctClass = clazz;\n        return clazz;\n    }\n\n    private boolean modified = false;\n\n    public boolean isModified() {\n        return modified;\n    }\n\n    public void setModified() {\n        this.modified = true;\n    }\n\n    @SuppressFBWarnings({\"EI_EXPOSE_REP\"})\n    // [ERROR] Medium: com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo.getClassLoader()\n    // may expose internal representation\n    // by returning ClassInfo.loader [com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo]\n    public ClassLoader getClassLoader() {\n        return loader;\n    }\n\n    private static String toClassName(@NonNull final String classFile) {\n        return classFile.replace('/', '.');\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/TtlTransformlet.java",
    "content": "package com.alibaba.ttl.threadpool.agent.transformlet;\n\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport javassist.CannotCompileException;\nimport javassist.NotFoundException;\n\nimport java.io.IOException;\n\n/**\n * TTL {@code Transformlet}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 3.0.0\n */\npublic interface TtlTransformlet {\n    /**\n     * info about class loader: may be <code>null</code> if the bootstrap loader.\n     * <p>\n     * more info see {@link java.lang.instrument.ClassFileTransformer#transform(java.lang.ClassLoader, java.lang.String, java.lang.Class, java.security.ProtectionDomain, byte[])}\n     *\n     * @see com.alibaba.ttl.threadpool.agent.TtlTransformer#transform(ClassLoader, String, Class, java.security.ProtectionDomain, byte[])\n     * @see java.lang.instrument.ClassFileTransformer#transform\n     */\n    void doTransform(@NonNull ClassInfo classInfo) throws CannotCompileException, NotFoundException, IOException;\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/helper/AbstractExecutorTtlTransformlet.java",
    "content": "package com.alibaba.ttl.threadpool.agent.transformlet.helper;\n\nimport com.alibaba.ttl.threadpool.TtlExecutors;\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport javassist.*;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\n\nimport static com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.isClassAtPackageJavaUtil;\nimport static com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.signatureOfMethod;\n\n/**\n * Abstract {@link TtlTransformlet} for {@link java.util.concurrent.Executor} and its subclass.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author wuwen5 (wuwen.55 at aliyun dot com)\n * @see java.util.concurrent.Executor\n * @see java.util.concurrent.ExecutorService\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ScheduledThreadPoolExecutor\n * @see java.util.concurrent.Executors\n * @see com.alibaba.ttl.threadpool.agent.transformlet.internal.PriorityBlockingQueueTtlTransformlet\n * @since 3.0.0\n */\npublic abstract class AbstractExecutorTtlTransformlet implements TtlTransformlet {\n    protected static final String RUNNABLE_CLASS_NAME = \"java.lang.Runnable\";\n    protected static final String CALLABLE_CLASS_NAME = \"java.util.concurrent.Callable\";\n\n    protected static final String TTL_RUNNABLE_CLASS_NAME = \"com.alibaba.ttl.TtlRunnable\";\n    protected static final String TTL_CALLABLE_CLASS_NAME = \"com.alibaba.ttl.TtlCallable\";\n\n    protected static final String THREAD_FACTORY_CLASS_NAME = \"java.util.concurrent.ThreadFactory\";\n    protected static final String THREAD_POOL_EXECUTOR_CLASS_NAME = \"java.util.concurrent.ThreadPoolExecutor\";\n\n    protected final Logger logger = Logger.getLogger(getClass());\n\n    protected final Set<String> executorClassNames;\n    protected final boolean disableInheritableForThreadPool;\n\n    private final Map<String, String> paramTypeNameToDecorateMethodClass = new HashMap<>();\n\n    /**\n     * @param executorClassNames the executor class names to be transformed\n     */\n    public AbstractExecutorTtlTransformlet(Set<String> executorClassNames, boolean disableInheritableForThreadPool) {\n        this.executorClassNames = Collections.unmodifiableSet(executorClassNames);\n        this.disableInheritableForThreadPool = disableInheritableForThreadPool;\n\n        paramTypeNameToDecorateMethodClass.put(RUNNABLE_CLASS_NAME, TTL_RUNNABLE_CLASS_NAME);\n        paramTypeNameToDecorateMethodClass.put(CALLABLE_CLASS_NAME, TTL_CALLABLE_CLASS_NAME);\n    }\n\n    @Override\n    public final void doTransform(@NonNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException {\n        // work-around ClassCircularityError:\n        //      https://github.com/alibaba/transmittable-thread-local/issues/278\n        //      https://github.com/alibaba/transmittable-thread-local/issues/234\n        if (isClassAtPackageJavaUtil(classInfo.getClassName())) return;\n\n        final CtClass clazz = classInfo.getCtClass();\n        if (executorClassNames.contains(classInfo.getClassName())) {\n            for (CtMethod method : clazz.getDeclaredMethods()) {\n                updateSubmitMethodsOfExecutorClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(method);\n            }\n\n            if (disableInheritableForThreadPool) updateConstructorDisableInheritable(clazz);\n\n            classInfo.setModified();\n        } else {\n            if (clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() || clazz.isAnnotation()) {\n                return;\n            }\n            if (!clazz.subclassOf(clazz.getClassPool().get(THREAD_POOL_EXECUTOR_CLASS_NAME))) return;\n\n            logger.info(\"Transforming class \" + classInfo.getClassName());\n\n            final boolean modified = updateBeforeAndAfterExecuteMethodOfExecutorSubclass(clazz);\n            if (modified) classInfo.setModified();\n        }\n    }\n\n    /**\n     * @see TtlTransformletHelper#doAutoWrap(Runnable)\n     * @see TtlTransformletHelper#doAutoWrap(Callable)\n     */\n    @SuppressFBWarnings(\"VA_FORMAT_STRING_USES_NEWLINE\") // [ERROR] Format string should use %n rather than \\n\n    private void updateSubmitMethodsOfExecutorClass_decorateToTtlWrapperAndSetAutoWrapperAttachment(@NonNull final CtMethod method) throws NotFoundException, CannotCompileException {\n        final int modifiers = method.getModifiers();\n        if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers)) return;\n\n        CtClass[] parameterTypes = method.getParameterTypes();\n        StringBuilder insertCode = new StringBuilder();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            final String paramTypeName = parameterTypes[i].getName();\n            if (paramTypeNameToDecorateMethodClass.containsKey(paramTypeName)) {\n                String code = String.format(\n                        // auto decorate to TTL wrapper\n                        \"$%d = com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.doAutoWrap($%<d);\",\n                        i + 1);\n                logger.info(\"insert code before method \" + signatureOfMethod(method) + \" of class \" + method.getDeclaringClass().getName() + \":\\n\" + code);\n                insertCode.append(code);\n            }\n        }\n        if (insertCode.length() > 0) {\n            logger.info(\"insert code before method \" + signatureOfMethod(method) + \" of class \" +\n                    method.getDeclaringClass().getName() + \":\\n\" + insertCode);\n            method.insertBefore(insertCode.toString());\n        }\n    }\n\n    /**\n     * @see TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)\n     */\n    private void updateConstructorDisableInheritable(@NonNull final CtClass clazz) throws NotFoundException, CannotCompileException {\n        for (CtConstructor constructor : clazz.getDeclaredConstructors()) {\n            final CtClass[] parameterTypes = constructor.getParameterTypes();\n            final StringBuilder insertCode = new StringBuilder();\n            for (int i = 0; i < parameterTypes.length; i++) {\n                final String paramTypeName = parameterTypes[i].getName();\n                if (THREAD_FACTORY_CLASS_NAME.equals(paramTypeName)) {\n                    String code = String.format(\"$%d = com.alibaba.ttl.threadpool.TtlExecutors.getDisableInheritableThreadFactory($%<d);\", i + 1);\n                    insertCode.append(code);\n                }\n            }\n            if (insertCode.length() > 0) {\n                logger.info(\"insert code before constructor \" + signatureOfMethod(constructor) + \" of class \" +\n                        constructor.getDeclaringClass().getName() + \": \" + insertCode);\n                constructor.insertBefore(insertCode.toString());\n            }\n        }\n    }\n\n    /**\n     * @see com.alibaba.ttl.spi.TtlAttachmentsDelegate#unwrapIfIsAutoWrapper(Object)\n     */\n    private boolean updateBeforeAndAfterExecuteMethodOfExecutorSubclass(@NonNull final CtClass clazz) throws NotFoundException, CannotCompileException {\n        final CtClass runnableClass = clazz.getClassPool().get(RUNNABLE_CLASS_NAME);\n        final CtClass threadClass = clazz.getClassPool().get(\"java.lang.Thread\");\n        final CtClass throwableClass = clazz.getClassPool().get(\"java.lang.Throwable\");\n        boolean modified = false;\n\n        try {\n            final CtMethod beforeExecute = clazz.getDeclaredMethod(\"beforeExecute\", new CtClass[]{threadClass, runnableClass});\n            // unwrap runnable if IsAutoWrapper\n            String code = \"$2 = com.alibaba.ttl.spi.TtlAttachmentsDelegate.unwrapIfIsAutoWrapper($2);\";\n            logger.info(\"insert code before method \" + signatureOfMethod(beforeExecute) + \" of class \" +\n                    beforeExecute.getDeclaringClass().getName() + \": \" + code);\n            beforeExecute.insertBefore(code);\n            modified = true;\n        } catch (NotFoundException e) {\n            // clazz does not override beforeExecute method, do nothing.\n        }\n\n        try {\n            final CtMethod afterExecute = clazz.getDeclaredMethod(\"afterExecute\", new CtClass[]{runnableClass, throwableClass});\n            // unwrap runnable if IsAutoWrapper\n            String code = \"$1 = com.alibaba.ttl.spi.TtlAttachmentsDelegate.unwrapIfIsAutoWrapper($1);\";\n            logger.info(\"insert code before method \" + signatureOfMethod(afterExecute) + \" of class \" +\n                    afterExecute.getDeclaringClass().getName() + \": \" + code);\n            afterExecute.insertBefore(code);\n            modified = true;\n        } catch (NotFoundException e) {\n            // clazz does not override afterExecute method, do nothing.\n        }\n\n        return modified;\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/helper/TtlTransformletHelper.java",
    "content": "package com.alibaba.ttl.threadpool.agent.transformlet.helper;\n\nimport com.alibaba.ttl.TtlCallable;\nimport com.alibaba.ttl.TtlRunnable;\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport edu.umd.cs.findbugs.annotations.Nullable;\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport javassist.*;\n\nimport java.lang.reflect.Modifier;\nimport java.net.URL;\nimport java.security.CodeSource;\nimport java.security.ProtectionDomain;\nimport java.util.concurrent.Callable;\n\nimport static com.alibaba.ttl.TransmittableThreadLocal.Transmitter.capture;\nimport static com.alibaba.ttl.spi.TtlAttachmentsDelegate.setAutoWrapperAttachment;\n\n/**\n * Helper methods for {@link TtlTransformlet} implementation.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @since 3.0.0\n */\npublic final class TtlTransformletHelper {\n    private static final Logger logger = Logger.getLogger(TtlTransformletHelper.class);\n\n    // ======== Javassist/Class Helper ========\n\n    /**\n     * Output string like {@code public ScheduledFuture scheduleAtFixedRate(Runnable, long, long, TimeUnit)}\n     * for {@link  java.util.concurrent.ScheduledThreadPoolExecutor#scheduleAtFixedRate}.\n     *\n     * @param method method object\n     * @return method signature string\n     */\n    @NonNull\n    public static String signatureOfMethod(@NonNull final CtBehavior method) throws NotFoundException {\n        final StringBuilder stringBuilder = new StringBuilder();\n\n        stringBuilder.append(Modifier.toString(method.getModifiers()));\n        if (method instanceof CtMethod) {\n            final String returnType = ((CtMethod) method).getReturnType().getSimpleName();\n            stringBuilder.append(\" \").append(returnType);\n        }\n        stringBuilder.append(\" \").append(method.getName()).append(\"(\");\n\n        final CtClass[] parameterTypes = method.getParameterTypes();\n        for (int i = 0; i < parameterTypes.length; i++) {\n            CtClass parameterType = parameterTypes[i];\n            if (i != 0) stringBuilder.append(\", \");\n            stringBuilder.append(parameterType.getSimpleName());\n        }\n\n        stringBuilder.append(\")\");\n        return stringBuilder.toString();\n    }\n\n    public static URL getLocationUrlOfClass(CtClass clazz) {\n        try {\n            // proxy classes is dynamic, no class file\n            if (clazz.getName().startsWith(\"com.sun.proxy.\")) return null;\n\n            return clazz.getURL();\n        } catch (Exception e) {\n            logger.warn(\"Fail to getLocationUrlOfClass \" + clazz.getName() + \", cause: \" + e.toString());\n            return null;\n        }\n    }\n\n    public static String getLocationFileOfClass(CtClass clazz) {\n        final URL location = getLocationUrlOfClass(clazz);\n        if (location == null) return null;\n\n        return location.getFile();\n    }\n\n    public static URL getLocationUrlOfClass(Class<?> clazz) {\n        try {\n            // proxy classes is dynamic, no class file\n            if (clazz.getName().startsWith(\"com.sun.proxy.\")) return null;\n\n            final ProtectionDomain protectionDomain = clazz.getProtectionDomain();\n            if (protectionDomain == null) return null;\n\n            final CodeSource codeSource = protectionDomain.getCodeSource();\n            if (codeSource == null) return null;\n\n            return codeSource.getLocation();\n        } catch (Exception e) {\n            logger.warn(\"Fail to getLocationUrlOfClass \" + clazz.getName() + \", cause: \" + e.toString());\n            return null;\n        }\n    }\n\n    public static String getLocationFileOfClass(Class<?> clazz) {\n        final URL location = getLocationUrlOfClass(clazz);\n        if (location == null) return null;\n\n        return location.getFile();\n    }\n\n    // ======== Method Transform Helper ========\n\n    @NonNull\n    public static String renamedMethodNameByTtl(@NonNull CtMethod method) {\n        return \"original$\" + method.getName() + \"$method$renamed$by$ttl\";\n    }\n\n    public static String addTryFinallyToMethod(@NonNull CtMethod method, @NonNull String beforeCode, @NonNull String finallyCode) throws CannotCompileException, NotFoundException {\n        return addTryFinallyToMethod(method, renamedMethodNameByTtl(method), beforeCode, finallyCode);\n    }\n\n    /**\n     * Add {@code try-finally} logic to method.\n     *\n     * @return the body code of method rewritten\n     */\n    public static String addTryFinallyToMethod(@NonNull CtMethod method, @NonNull String nameForOriginalMethod, @NonNull String beforeCode, @NonNull String finallyCode) throws CannotCompileException, NotFoundException {\n        final CtClass clazz = method.getDeclaringClass();\n\n        final CtMethod newMethod = CtNewMethod.copy(method, clazz, null);\n        // rename original method, and set to private method(avoid reflect out renamed method unexpectedly)\n        newMethod.setName(nameForOriginalMethod);\n        newMethod.setModifiers(newMethod.getModifiers()\n                & ~Modifier.PUBLIC /* remove public */\n                & ~Modifier.PROTECTED /* remove protected */\n                | Modifier.PRIVATE /* add private */);\n        clazz.addMethod(newMethod);\n\n        final String returnOp;\n        if (method.getReturnType() == CtClass.voidType) {\n            returnOp = \"\";\n        } else {\n            returnOp = \"return \";\n        }\n        // set new method implementation\n        final String code = \"{\\n\" +\n                beforeCode + \"\\n\" +\n                \"try {\\n\" +\n                \"    \" + returnOp + nameForOriginalMethod + \"($$);\\n\" +\n                \"} finally {\\n\" +\n                \"    \" + finallyCode + \"\\n\" +\n                \"} }\";\n        method.setBody(code);\n\n        return code;\n    }\n\n    // ======== CRR Helper ========\n\n    @Nullable\n    public static Object doCaptureIfNotTtlEnhanced(@Nullable Object obj) {\n        if (obj instanceof TtlEnhanced) return null;\n        else return capture();\n    }\n\n\n    // FIXME hard-coded for type Runnable, not generic!\n    @Nullable\n    public static Runnable doAutoWrap(@Nullable final Runnable runnable) {\n        if (runnable == null) return null;\n\n        final TtlRunnable ret = TtlRunnable.get(runnable, false, true);\n\n        // have been auto wrapped?\n        if (ret != runnable) setAutoWrapperAttachment(ret);\n\n        return ret;\n    }\n\n    // FIXME hard-coded for type Callable, not generic!\n    @Nullable\n    public static <T> Callable<T> doAutoWrap(@Nullable final Callable<T> callable) {\n        if (callable == null) return null;\n\n        final TtlCallable<T> ret = TtlCallable.get(callable, false, true);\n\n        // have been auto wrapped?\n        if (ret != callable) setAutoWrapperAttachment(ret);\n\n        return ret;\n    }\n\n    // ======== class/package info Helper ========\n\n    @NonNull\n    public static String getPackageName(@NonNull String className) {\n        final int idx = className.lastIndexOf('.');\n        if (-1 == idx) return \"\";\n\n        return className.substring(0, idx);\n    }\n\n    public static boolean isClassAtPackage(@NonNull String className, @NonNull String packageName) {\n        return packageName.equals(getPackageName(className));\n    }\n\n    public static boolean isClassUnderPackage(@NonNull String className, @NonNull String packageName) {\n        String packageOfClass = getPackageName(className);\n        return packageOfClass.equals(packageName) || packageOfClass.startsWith(packageName + \".\");\n    }\n\n    public static boolean isClassAtPackageJavaUtil(@NonNull String className) {\n        return isClassAtPackage(className, \"java.util\");\n    }\n\n    @SuppressFBWarnings(\"CT_CONSTRUCTOR_THROW\")\n    private TtlTransformletHelper() {\n        throw new InstantiationError(\"Must not instantiate this class\");\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/helper/package-info.java",
    "content": "/**\n * Helper API for TTL Agent extension {@code Transformlet} development.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet\n * @since 3.0.0\n */\npackage com.alibaba.ttl.threadpool.agent.transformlet.helper;\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/internal/ForkJoinTtlTransformlet.java",
    "content": "package com.alibaba.ttl.threadpool.agent.transformlet.internal;\n\nimport com.alibaba.ttl.spi.TtlEnhanced;\nimport com.alibaba.ttl.threadpool.agent.TtlAgent;\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport javassist.*;\n\nimport java.io.IOException;\n\nimport static com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.*;\n\n/**\n * {@link TtlTransformlet} for {@link java.util.concurrent.ForkJoinTask}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author wuwen5 (wuwen.55 at aliyun dot com)\n * @see java.util.concurrent.ForkJoinPool\n * @see java.util.concurrent.ForkJoinTask\n * @since 2.5.1\n */\npublic final class ForkJoinTtlTransformlet implements TtlTransformlet {\n    private static final Logger logger = Logger.getLogger(ForkJoinTtlTransformlet.class);\n\n    private static final String FORK_JOIN_TASK_CLASS_NAME = \"java.util.concurrent.ForkJoinTask\";\n    private static final String FORK_JOIN_POOL_CLASS_NAME = \"java.util.concurrent.ForkJoinPool\";\n    private static final String FORK_JOIN_WORKER_THREAD_FACTORY_CLASS_NAME = \"java.util.concurrent.ForkJoinPool$ForkJoinWorkerThreadFactory\";\n\n    private final boolean disableInheritableForThreadPool;\n\n    public ForkJoinTtlTransformlet() {\n        this.disableInheritableForThreadPool = TtlAgent.isDisableInheritableForThreadPool();\n    }\n\n    @Override\n    public void doTransform(@NonNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException {\n        if (FORK_JOIN_TASK_CLASS_NAME.equals(classInfo.getClassName())) {\n            updateForkJoinTaskClass(classInfo.getCtClass());\n            classInfo.setModified();\n        } else if (disableInheritableForThreadPool && FORK_JOIN_POOL_CLASS_NAME.equals(classInfo.getClassName())) {\n            updateConstructorDisableInheritable(classInfo.getCtClass());\n            classInfo.setModified();\n        }\n    }\n\n    /**\n     * @see com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper#doCaptureIfNotTtlEnhanced(Object)\n     */\n    private void updateForkJoinTaskClass(@NonNull final CtClass clazz) throws CannotCompileException, NotFoundException {\n        final String className = clazz.getName();\n\n        // add new field\n        final String capturedFieldName = \"captured$field$added$by$ttl\";\n        final CtField capturedField = CtField.make(\"private final Object \" + capturedFieldName + \";\", clazz);\n        clazz.addField(capturedField, \"com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.doCaptureIfNotTtlEnhanced(this);\");\n        logger.info(\"add new field \" + capturedFieldName + \" to class \" + className);\n\n        final CtMethod doExecMethod = clazz.getDeclaredMethod(\"doExec\", new CtClass[0]);\n        final String doExec_renamed_method_name = renamedMethodNameByTtl(doExecMethod);\n\n        final String beforeCode = \"if (this instanceof \" + TtlEnhanced.class.getName() + \") {\\n\" + // if the class is already TTL enhanced(eg: com.alibaba.ttl.TtlRecursiveTask)\n                \"    return \" + doExec_renamed_method_name + \"($$);\\n\" +                           // return directly/do nothing\n                \"}\\n\" +\n                \"Object backup = com.alibaba.ttl.TransmittableThreadLocal.Transmitter.replay(\" + capturedFieldName + \");\";\n\n        final String finallyCode = \"com.alibaba.ttl.TransmittableThreadLocal.Transmitter.restore(backup);\";\n\n        final String code = addTryFinallyToMethod(doExecMethod, doExec_renamed_method_name, beforeCode, finallyCode);\n        logger.info(\"insert code around method \" + signatureOfMethod(doExecMethod) + \" of class \" + clazz.getName() + \": \" + code);\n    }\n\n    private void updateConstructorDisableInheritable(@NonNull final CtClass clazz) throws NotFoundException, CannotCompileException {\n        for (CtConstructor constructor : clazz.getDeclaredConstructors()) {\n            final CtClass[] parameterTypes = constructor.getParameterTypes();\n            final StringBuilder insertCode = new StringBuilder();\n            for (int i = 0; i < parameterTypes.length; i++) {\n                final String paramTypeName = parameterTypes[i].getName();\n                if (FORK_JOIN_WORKER_THREAD_FACTORY_CLASS_NAME.equals(paramTypeName)) {\n                    String code = String.format(\"$%d = com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper.getDisableInheritableForkJoinWorkerThreadFactory($%<d);\", i + 1);\n                    insertCode.append(code);\n                }\n            }\n            if (insertCode.length() > 0) {\n                logger.info(\"insert code before method \" + signatureOfMethod(constructor) + \" of class \" +\n                    constructor.getDeclaringClass().getName() + \": \" + insertCode);\n                constructor.insertBefore(insertCode.toString());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/internal/JdkExecutorTtlTransformlet.java",
    "content": "package com.alibaba.ttl.threadpool.agent.transformlet.internal;\n\nimport com.alibaba.ttl.threadpool.agent.TtlAgent;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport com.alibaba.ttl.threadpool.agent.transformlet.helper.AbstractExecutorTtlTransformlet;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * {@link TtlTransformlet} for {@link java.util.concurrent.ThreadPoolExecutor}\n * and {@link java.util.concurrent.ScheduledThreadPoolExecutor}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author wuwen5 (wuwen.55 at aliyun dot com)\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ScheduledThreadPoolExecutor\n * @since 2.5.1\n */\npublic final class JdkExecutorTtlTransformlet extends AbstractExecutorTtlTransformlet implements TtlTransformlet {\n\n    private static Set<String> getExecutorClassNames() {\n        Set<String> executorClassNames = new HashSet<>();\n\n        executorClassNames.add(THREAD_POOL_EXECUTOR_CLASS_NAME);\n        executorClassNames.add(\"java.util.concurrent.ScheduledThreadPoolExecutor\");\n\n        return executorClassNames;\n    }\n\n    public JdkExecutorTtlTransformlet() {\n        super(getExecutorClassNames(), TtlAgent.isDisableInheritableForThreadPool());\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/internal/PriorityBlockingQueueTtlTransformlet.java",
    "content": "package com.alibaba.ttl.threadpool.agent.transformlet.internal;\n\nimport com.alibaba.ttl.threadpool.TtlExecutors;\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport javassist.CannotCompileException;\nimport javassist.CtClass;\nimport javassist.CtConstructor;\nimport javassist.NotFoundException;\n\nimport java.io.IOException;\nimport java.util.Comparator;\n\nimport static com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.signatureOfMethod;\n\n/**\n * TTL {@link TtlTransformlet} for {@link java.util.concurrent.PriorityBlockingQueue PriorityBlockingQueue}.\n * <p>\n * Avoid {@code ClassCastException(TtlRunnable cannot be cast to Comparable)} problem\n * for combination usage:\n * <ul>\n * <li>use {@link java.util.concurrent.PriorityBlockingQueue PriorityBlockingQueue} for {@link java.util.concurrent.ThreadPoolExecutor ThreadPoolExecutor}</li>\n * <li>use {@code TTL Agent} {@link JdkExecutorTtlTransformlet}</li>\n * </ul>\n * More info see <a href=\"https://github.com/alibaba/transmittable-thread-local/issues/330\">issue #330</a>\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see TtlExecutors#getTtlRunnableUnwrapComparator(Comparator)\n * @see TtlExecutors#getTtlRunnableUnwrapComparatorForComparableRunnable()\n * @see java.util.concurrent.ThreadPoolExecutor\n * @see java.util.concurrent.ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue)\n * @see java.util.concurrent.PriorityBlockingQueue\n * @see java.util.concurrent.PriorityBlockingQueue#PriorityBlockingQueue(int, Comparator)\n * @see java.util.PriorityQueue\n * @see java.util.PriorityQueue#PriorityQueue(int, Comparator)\n * @see JdkExecutorTtlTransformlet\n * @since 2.12.3\n */\npublic class PriorityBlockingQueueTtlTransformlet implements TtlTransformlet {\n    private static final Logger logger = Logger.getLogger(PriorityBlockingQueueTtlTransformlet.class);\n\n    private static final String PRIORITY_BLOCKING_QUEUE_CLASS_NAME = \"java.util.concurrent.PriorityBlockingQueue\";\n    private static final String PRIORITY_QUEUE_CLASS_NAME = \"java.util.PriorityQueue\";\n    private static final String COMPARATOR_FIELD_NAME = \"comparator\";\n\n    @Override\n    public void doTransform(@NonNull ClassInfo classInfo) throws IOException, CannotCompileException, NotFoundException {\n        final String className = classInfo.getClassName();\n\n        if (PRIORITY_BLOCKING_QUEUE_CLASS_NAME.equals(className)) {\n            updatePriorityBlockingQueueClass(classInfo.getCtClass());\n            classInfo.setModified();\n        }\n\n        if (PRIORITY_QUEUE_CLASS_NAME.equals(className)) {\n            updateBlockingQueueClass(classInfo.getCtClass());\n            classInfo.setModified();\n        }\n    }\n\n    private void updatePriorityBlockingQueueClass(@NonNull final CtClass clazz) throws CannotCompileException, NotFoundException {\n        if (!haveComparatorField(clazz)) {\n            // In Java 6, PriorityBlockingQueue implementation do not have field comparator,\n            // need transform more fundamental class PriorityQueue\n            logger.info(PRIORITY_BLOCKING_QUEUE_CLASS_NAME + \" do not have field \" + COMPARATOR_FIELD_NAME +\n                    \", transform \" + PRIORITY_QUEUE_CLASS_NAME + \" instead.\");\n            return;\n        }\n\n        modifyConstructors(clazz);\n    }\n\n    private void updateBlockingQueueClass(@NonNull final CtClass clazz) throws CannotCompileException, NotFoundException {\n        final CtClass classPriorityBlockingQueue = clazz.getClassPool().getCtClass(PRIORITY_BLOCKING_QUEUE_CLASS_NAME);\n        if (haveComparatorField(classPriorityBlockingQueue)) return;\n\n        logger.info(PRIORITY_BLOCKING_QUEUE_CLASS_NAME + \" do not have field \" + COMPARATOR_FIELD_NAME +\n                \", so need transform \" + PRIORITY_QUEUE_CLASS_NAME);\n        modifyConstructors(clazz);\n    }\n\n    private static boolean haveComparatorField(CtClass clazz) {\n        try {\n            clazz.getDeclaredField(COMPARATOR_FIELD_NAME);\n            return true;\n        } catch (NotFoundException e) {\n            return false;\n        }\n    }\n\n    /**\n     * wrap comparator field in constructors\n     */\n    private static final String CODE = \"this.\" + COMPARATOR_FIELD_NAME + \" = \"\n            + PriorityBlockingQueueTtlTransformlet.class.getName() +\n            \".overwriteComparatorField$by$ttl(this.\" + COMPARATOR_FIELD_NAME + \");\";\n\n    /**\n     * @see #overwriteComparatorField$by$ttl(Comparator)\n     */\n    private static void modifyConstructors(@NonNull CtClass clazz) throws NotFoundException, CannotCompileException {\n        for (CtConstructor constructor : clazz.getDeclaredConstructors()) {\n            logger.info(\"insert code after constructor \" + signatureOfMethod(constructor) + \" of class \" +\n                    constructor.getDeclaringClass().getName() + \": \" + CODE);\n\n            constructor.insertAfter(CODE);\n        }\n    }\n\n    /**\n     * @see TtlExecutors#getTtlRunnableUnwrapComparator(Comparator)\n     */\n    public static Comparator<Runnable> overwriteComparatorField$by$ttl(Comparator<Runnable> comparator) {\n        if (comparator == null) return TtlExecutors.getTtlRunnableUnwrapComparatorForComparableRunnable();\n\n        return TtlExecutors.getTtlRunnableUnwrapComparator(comparator);\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/internal/TimerTaskTtlTransformlet.java",
    "content": "package com.alibaba.ttl.threadpool.agent.transformlet.internal;\n\nimport com.alibaba.ttl.threadpool.agent.logging.Logger;\nimport com.alibaba.ttl.threadpool.agent.transformlet.ClassInfo;\nimport com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet;\nimport edu.umd.cs.findbugs.annotations.NonNull;\nimport javassist.*;\n\nimport java.io.IOException;\n\nimport static com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.*;\n\n/**\n * {@link TtlTransformlet} for {@link java.util.TimerTask}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @author wuwen5 (wuwen.55 at aliyun dot com)\n * @see java.util.TimerTask\n * @see java.util.Timer\n * @since 2.7.0\n */\npublic final class TimerTaskTtlTransformlet implements TtlTransformlet {\n    private static final Logger logger = Logger.getLogger(TimerTaskTtlTransformlet.class);\n\n    private static final String TIMER_TASK_CLASS_NAME = \"java.util.TimerTask\";\n    private static final String RUN_METHOD_NAME = \"run\";\n\n    @Override\n    public void doTransform(@NonNull final ClassInfo classInfo) throws IOException, NotFoundException, CannotCompileException {\n        // work-around ClassCircularityError:\n        if (isClassAtPackageJavaUtil(classInfo.getClassName())) return;\n\n        // TimerTask class is checked by above logic.\n        //\n        // if (TIMER_TASK_CLASS_NAME.equals(classInfo.getClassName())) return; // No need transform TimerTask class\n\n        final CtClass clazz = classInfo.getCtClass();\n\n        if (clazz.isPrimitive() || clazz.isArray() || clazz.isInterface() || clazz.isAnnotation()) {\n            return;\n        }\n        // class contains method `void run()` ?\n        try {\n            final CtMethod runMethod = clazz.getDeclaredMethod(RUN_METHOD_NAME, new CtClass[0]);\n            if (!CtClass.voidType.equals(runMethod.getReturnType())) return;\n        } catch (NotFoundException e) {\n            return;\n        }\n        if (!clazz.subclassOf(clazz.getClassPool().get(TIMER_TASK_CLASS_NAME))) return;\n\n        logger.info(\"Transforming class \" + classInfo.getClassName());\n\n        updateTimerTaskClass(clazz);\n        classInfo.setModified();\n    }\n\n    /**\n     * @see com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper#doCaptureIfNotTtlEnhanced(Object)\n     */\n    private void updateTimerTaskClass(@NonNull final CtClass clazz) throws CannotCompileException, NotFoundException {\n        final String className = clazz.getName();\n\n        // add new field\n        final String capturedFieldName = \"captured$field$added$by$ttl\";\n        final CtField capturedField = CtField.make(\"private final Object \" + capturedFieldName + \";\", clazz);\n        clazz.addField(capturedField, \"com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.doCaptureIfNotTtlEnhanced(this);\");\n        logger.info(\"add new field \" + capturedFieldName + \" to class \" + className);\n\n        final CtMethod runMethod = clazz.getDeclaredMethod(RUN_METHOD_NAME, new CtClass[0]);\n\n        final String beforeCode = \"Object backup = com.alibaba.ttl.TransmittableThreadLocal.Transmitter.replay(\" + capturedFieldName + \");\";\n        final String finallyCode = \"com.alibaba.ttl.TransmittableThreadLocal.Transmitter.restore(backup);\";\n\n        final String code = addTryFinallyToMethod(runMethod, beforeCode, finallyCode);\n        logger.info(\"insert code around method \" + signatureOfMethod(runMethod) + \" of class \" + clazz.getName() + \": \" + code);\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/internal/package-info.java",
    "content": "/**\n * TTL built-in {@code Transformlet} implementations.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.threadpool.agent.transformlet.internal.JdkExecutorTtlTransformlet\n * @see com.alibaba.ttl.threadpool.agent.transformlet.internal.ForkJoinTtlTransformlet\n * @see com.alibaba.ttl.threadpool.agent.transformlet.internal.TimerTaskTtlTransformlet\n * @see com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet\n * @since 3.0.0\n */\npackage com.alibaba.ttl.threadpool.agent.transformlet.internal;\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/agent/transformlet/package-info.java",
    "content": "/**\n * TTL {@code Transformlet} API for TTL Agent extension {@code Transformlet} development.\n * <p>\n * TTL built-in {@code Transformlet} implementations is in the package {@link com.alibaba.ttl.threadpool.agent.transformlet.internal}.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.threadpool.agent.transformlet.TtlTransformlet\n * @since 3.0.0\n */\npackage com.alibaba.ttl.threadpool.agent.transformlet;\n"
  },
  {
    "path": "ttl2-compatible/src/main/java/com/alibaba/ttl/threadpool/package-info.java",
    "content": "/**\n * Thread pool wrap/decoration utils.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.threadpool.TtlExecutors\n * @see com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper\n */\npackage com.alibaba.ttl.threadpool;\n"
  },
  {
    "path": "ttl2-compatible/src/main/javadoc/overview.html",
    "content": "<html>\n<body>\n<p>This is the API documentation for the\n    <a href=\"https://github.com/alibaba/transmittable-thread-local\" target=\"_top\">📌 TransmittableThreadLocal(TTL)</a>,\n    The missing Java™ std lib(simple &amp; 0-dependency) for framework/middleware,\n    provide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.\n</p>\n</body>\n</html>\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/Utils.kt",
    "content": "package com.alibaba\n\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.threadpool.agent.TtlAgent\nimport io.kotest.assertions.withClue\nimport io.kotest.matchers.booleans.shouldBeFalse\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport mu.KotlinLogging\nimport java.lang.Thread.sleep\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.ConcurrentMap\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.ThreadPoolExecutor\n\n\nprivate val logger = KotlinLogging.logger {}\n\n\n/**\n * Expand thread pool, to pre-create and cache threads.\n */\nfun expandThreadPool(executor: ExecutorService) {\n    val cpuCountX2 = Runtime.getRuntime().availableProcessors() * 2\n    val count = if (executor is ThreadPoolExecutor) {\n        (executor.maximumPoolSize * 2).coerceAtMost(cpuCountX2)\n    } else cpuCountX2\n\n    (0 until count).map {\n        executor.submit { sleep(10) }\n    }.forEach { it.get() }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n// TTL Instances\n////////////////////////////////////////////////////////////////////////////////\n\ninternal const val PARENT_CREATE_MODIFIED_IN_CHILD = \"parent-create-modified-in-child\"\ninternal const val PARENT_CREATE_UNMODIFIED_IN_CHILD = \"parent-create-unmodified-in-child\"\ninternal const val PARENT_CREATE_AFTER_CREATE_CHILD = \"parent-create-after-create-child\"\ninternal const val CHILD_CREATE = \"child-create\"\n\ntypealias  TtlInstances<T> = ConcurrentMap<String, TransmittableThreadLocal<T>>\n\nfun createParentTtlInstances(ttlInstances: TtlInstances<String> = ConcurrentHashMap()): TtlInstances<String> {\n    listOf(PARENT_CREATE_UNMODIFIED_IN_CHILD, PARENT_CREATE_MODIFIED_IN_CHILD).forEach {\n        newTtlInstanceAndPut(it, ttlInstances)\n    }\n    return ttlInstances\n}\n\nfun createParentTtlInstancesAfterCreateChild(ttlInstances: TtlInstances<String>) {\n    newTtlInstanceAndPut(PARENT_CREATE_AFTER_CREATE_CHILD, ttlInstances)\n}\n\nfun createChildTtlInstancesAndModifyParentTtlInstances(\n    tag: String,\n    ttlInstances: TtlInstances<String>\n): TtlValues<String> {\n    // 1. Add new\n    val newChildKey = \"$CHILD_CREATE$tag\"\n    newTtlInstanceAndPut(newChildKey, ttlInstances)\n\n    // 2. modify the parent key\n    val ttl: TransmittableThreadLocal<String>? = ttlInstances[PARENT_CREATE_MODIFIED_IN_CHILD]\n    ttl!!.set(\"${ttl.get()}$tag\")\n\n    return copyTtlValues(ttlInstances)\n}\n\nfun modifyParentTtlInstances(tag: String, ttlInstances: TtlInstances<String>): TtlValues<String> {\n    // modify the parent key\n    val ttl: TransmittableThreadLocal<String>? = ttlInstances[PARENT_CREATE_MODIFIED_IN_CHILD]\n    ttl!!.set(\"${ttl.get()}$tag\")\n\n    return copyTtlValues(ttlInstances)\n}\n\nfun newTtlInstanceAndPut(key: String, ttlInstances: TtlInstances<String>): TransmittableThreadLocal<String> {\n    val ttl = object : TransmittableThreadLocal<String>() {\n        override fun toString(): String {\n            return \"${super.toString()}(${get()})\"\n        }\n    }\n    ttl.set(key)\n\n    val old = ttlInstances.putIfAbsent(key, ttl)\n    withClue(\"Already contains key $key\") {\n        old.shouldBeNull()\n    }\n\n    return ttl\n}\n\nfun <T> printTtlInstances(ttlInstances: TtlInstances<T>, title: String = \"\") {\n    val headList =\n        if (title.isBlank()) emptyList()\n        else listOf(\"## $title [${Thread.currentThread().name}] ##\")\n    val valueString = ttlInstances.filterValues { it.get() != null }\n        .map { (k, v) -> \"$k: ${v.get()}\" }\n        .joinToString()\n    val output = (headList + valueString + \"^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\")\n        .filter { it.isNotBlank() }\n        .joinToString(\"\\n\")\n    println(output)\n}\n\n\n////////////////////////////////////////////////////////////////////////////////\n// TTL Values\n////////////////////////////////////////////////////////////////////////////////\n\ntypealias  TtlValues<T> = Map<String, T>\n\nfun <T> copyTtlValues(ttlInstances: TtlInstances<T>): TtlValues<T> =\n    ttlInstances.filterValues { it.get() != null }\n        .mapValues { (_, v) -> v.get() }\n\nfun <T> assertTtlValues(expected: TtlValues<T>, copied: TtlValues<T>) {\n    copied shouldBe expected\n}\n\nfun <T> assertChildTtlValues(tag: String, values: TtlValues<T>) {\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD + tag,\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            CHILD_CREATE + tag to CHILD_CREATE + tag\n        ),\n        values\n    )\n}\n\nfun <T> assertChildTtlValuesWithParentCreateAfterCreateChild(tag: String, values: TtlValues<T>) {\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD + tag,\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            CHILD_CREATE + tag to CHILD_CREATE + tag,\n            PARENT_CREATE_AFTER_CREATE_CHILD to PARENT_CREATE_AFTER_CREATE_CHILD\n        ),\n        values\n    )\n}\n\nfun <T> assertParentTtlValues(values: TtlValues<T>) {\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD, // restored after call!\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            PARENT_CREATE_AFTER_CREATE_CHILD to PARENT_CREATE_AFTER_CREATE_CHILD\n        ),\n        values\n    )\n}\n\nfun hasTtlAgentRun(): Boolean = TtlAgent.isTtlAgentLoaded().also {\n    val key = \"run-ttl-test-under-agent\"\n    if (it) {\n        System.getProperties().containsKey(key).shouldBeTrue()\n        System.getProperty(key) shouldBe \"true\"\n    } else {\n        System.getProperties().containsKey(key).shouldBeFalse()\n    }\n}\n\nfun noTtlAgentRun(): Boolean = !hasTtlAgentRun()\n\nfun hasTtlAgentRunWithDisableInheritableForThreadPool(): Boolean =\n    hasTtlAgentRun() and TtlAgent.isDisableInheritableForThreadPool().also {\n        val key = \"run-ttl-test-under-agent-with-disable-inheritable\"\n        if (System.getProperties().containsKey(key)) {\n            System.getProperty(key) shouldBe \"true\"\n            it.shouldBeTrue()\n\n            hasTtlAgentRun().shouldBeTrue()\n        }\n    }\n\nfun hasTtlAgentRunWithEnableTimerTask(): Boolean = hasTtlAgentRun() and TtlAgent.isEnableTimerTask().also {\n    val key = \"run-ttl-test-under-agent-with-enable-timer-task\"\n    if (System.getProperties().containsKey(key)) {\n        System.getProperty(key) shouldBe \"true\"\n        it.shouldBeTrue()\n\n        hasTtlAgentRun().shouldBeTrue()\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/coroutine/CoroutineDemo.kt",
    "content": "package  com.alibaba.demo.coroutine\n\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.async\nimport kotlinx.coroutines.runBlocking\n\n/**\n * Kotlin coroutine related material:\n *\n * - Official docs:\n *      - [Coroutines Guide - Kotlin Programming Language](https://kotlinlang.org/docs/reference/coroutines/coroutines-guide.html)\n *      - [Coroutine Context and Dispatchers - Kotlin Programming Language](https://kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html)\n *      - [Structured concurrency – Roman Elizarov](https://medium.com/@elizarov/structured-concurrency-722d765aa952)\n *      - [Kotlin/kotlin-coroutines-examples: Design documents and examples for coroutines in Kotlin - github.com](https://github.com/Kotlin/kotlin-coroutines-examples)\n * - others\n *      - [Demystifying Kotlin Coroutines – ProAndroidDev](https://proandroiddev.com/demystifying-kotlin-coroutines-6fe1f410570b)\n *      - [Kotlin coroutines in Spring - Code for glory](https://blog.alexnesterov.com/post/kotlin-coroutines-in-spring/)\n *      - [Kotlin coroutines and Spring 5 - Code for glory](https://blog.alexnesterov.com/post/kotlin-coroutines-and-spring-5/)\n */\nfun main(): Unit = runBlocking {\n    println(\"[${Thread.currentThread().name}] main\")\n\n    val deferred = async(Dispatchers.IO) {\n        println(\"[${Thread.currentThread().name}] async\")\n        \"world\"\n    }\n\n    println(\"[${Thread.currentThread().name}] Hello ${deferred.await()}!\")\n}\n\n\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/coroutine/CoroutineThreadContextElementDemo.kt",
    "content": "package  com.alibaba.demo.coroutine\n\nimport kotlinx.coroutines.*\n\nprivate val threadLocal = ThreadLocal<String?>() // declare thread-local variable\n\n/**\n * [Thread-local data - Coroutine Context and Dispatchers - Kotlin Programming Language](https://kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html#thread-local-data)\n */\nfun main() = runBlocking {\n    threadLocal.set(\"main\")\n    println(\"Pre-main, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n\n    val block: suspend CoroutineScope.() -> Unit = {\n        println(\"Launch start, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n        yield()\n        println(\"After yield, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n    }\n\n    println()\n    launch(block = block).join()\n\n    println()\n    launch(threadLocal.asContextElement(value = \"launch\"), block = block).join()\n\n    println()\n    launch(Dispatchers.Default, block = block).join()\n\n    println()\n    launch(Dispatchers.Default + threadLocal.asContextElement(value = \"launch\"), block = block).join()\n\n    println()\n    println(\"Post-main, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/coroutine/CoroutineThreadContextElementTest.kt",
    "content": "package com.alibaba.demo.coroutine\n\nimport io.kotest.core.spec.style.AnnotationSpec\nimport kotlinx.coroutines.*\nimport mu.KotlinLogging\nimport org.junit.Assert.*\n\nclass CoroutineThreadContextElementTest : AnnotationSpec() {\n    private val logger = KotlinLogging.logger {}\n\n    @Test\n    fun threadContextElement_passByValue(): Unit = runBlocking {\n        val mainValue = \"main-${System.currentTimeMillis()}\"\n        val launchValue = \"launch-${System.currentTimeMillis()}\"\n        val testThread = Thread.currentThread()\n\n        // String ThreadLocal, String is immutable value, can only be passed by value\n        val threadLocal = ThreadLocal<String?>()\n        threadLocal.set(mainValue)\n        logger.info { \"test thread - thread local value: ${threadLocal.get()}\" }\n\n        val job = launch(Dispatchers.Default + threadLocal.asContextElement(value = launchValue)) {\n            logger.info { \"launch thread - launch start, thread local value: ${threadLocal.get()}\" }\n            assertEquals(launchValue, threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay, thread local value: ${threadLocal.get()}\" }\n            assertEquals(launchValue, threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            val reset = \"job-reset-${threadLocal.get()}\"\n            threadLocal.set(reset)\n            assertEquals(reset, threadLocal.get())\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay set reset, thread local value: ${threadLocal.get()}\" }\n            // !!! After suspended delay function, reset ThreadLocal value is lost !!!\n            // assertEquals(reset, threadLocal.get())\n            assertEquals(launchValue, threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n        }\n        job.join()\n\n        logger.info { \"test thread - after launch, thread local value: ${threadLocal.get()}\" }\n\n        assertEquals(mainValue, threadLocal.get())\n    }\n\n    @Test\n    fun threadContextElement_passByReference(): Unit = runBlocking {\n        data class Reference(var data: Int = 42)\n\n        val mainValue = Reference()\n        val launchValue = Reference(4242)\n        val testThread = Thread.currentThread()\n\n        // Reference ThreadLocal, mutable value, pass by reference\n        val threadLocal = ThreadLocal<Reference>() // declare thread-local variable\n        threadLocal.set(mainValue)\n        logger.info { \"test thread - thread local value: ${threadLocal.get()}\" }\n\n        val job = launch(Dispatchers.Default + threadLocal.asContextElement(value = launchValue)) {\n            logger.info { \"launch thread - launch start, thread local value: ${threadLocal.get()}\" }\n            assertEquals(launchValue, threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay, thread local value: ${threadLocal.get()}\" }\n            assertEquals(launchValue, threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            val reset = -42\n            threadLocal.get().data = reset\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay set reset, thread local value: ${threadLocal.get()}\" }\n            assertEquals(Reference(reset), threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n        }\n        job.join()\n\n        logger.info { \"test thread - after launch in test thread, thread local value: ${threadLocal.get()}\" }\n        assertEquals(mainValue, threadLocal.get())\n    }\n\n    @Test\n    fun twoThreadContextElement(): Unit = runBlocking {\n        val mainValue = \"main-a-${System.currentTimeMillis()}\"\n        val testThread = Thread.currentThread()\n        val anotherMainValue = \"main-another-${System.currentTimeMillis()}\"\n\n        val threadLocal = ThreadLocal<String?>() // declare thread-local variable\n        val anotherThreadLocal = ThreadLocal<String?>() // declare thread-local variable\n\n        threadLocal.set(mainValue)\n        anotherThreadLocal.set(anotherMainValue)\n        logger.info { \"test thread - thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n\n        val launch1Value = \"aLaunch1\"\n        launch(Dispatchers.Default + threadLocal.asContextElement(value = launch1Value)) {\n            assertEquals(launch1Value, threadLocal.get())\n            assertNull(anotherThreadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n            assertEquals(launch1Value, threadLocal.get())\n            assertNull(anotherThreadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            val resetA = \"job-reset-${threadLocal.get()}\"\n            threadLocal.set(resetA)\n            val resetAnother = \"job-reset-${anotherThreadLocal.get()}\"\n            anotherThreadLocal.set(resetAnother)\n            logger.info { \"launch thread - before delay set reset, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay set reset, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n            // !!! After suspended delay function, reset ThreadLocal value is lost !!!\n            // assertEquals(resetA, threadLocal.get())\n            assertEquals(launch1Value, threadLocal.get())\n            // !!! After suspended delay, ThreadLocal without ThreadContextElement is not clear !!!\n            assertEquals(resetAnother, anotherThreadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n        }.join()\n\n        logger.info { \"test thread - after launch1, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n        assertEquals(mainValue, threadLocal.get())\n        assertEquals(anotherMainValue, anotherThreadLocal.get())\n\n        val launch2Value = \"aLaunch2\"\n        val anotherLaunch2Value = \"anotherLaunch2\"\n        launch(\n            Dispatchers.Default + threadLocal.asContextElement(value = launch2Value) + anotherThreadLocal.asContextElement(\n                value = anotherLaunch2Value\n            )\n        ) {\n            logger.info { \"launch thread - launch start, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n            assertEquals(launch2Value, threadLocal.get())\n            assertEquals(anotherLaunch2Value, anotherThreadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n            assertEquals(launch2Value, threadLocal.get())\n            assertEquals(anotherLaunch2Value, anotherThreadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            val resetA = \"job-reset-${threadLocal.get()}\"\n            threadLocal.set(resetA)\n            val resetAnother = \"job-reset-${anotherThreadLocal.get()}\"\n            anotherThreadLocal.set(resetAnother)\n            logger.info { \"launch thread - before delay set reset, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay set reset, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n            // !!! After suspended delay function, reset ThreadLocal value is lost !!!\n            // assertEquals(resetA, threadLocal.get())\n            // assertEquals(resetAnother, anotherThreadLocal.get())\n            assertEquals(launch2Value, threadLocal.get())\n            assertEquals(anotherLaunch2Value, anotherThreadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n        }.join()\n\n        logger.info { \"test thread - after launch2, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n        assertEquals(mainValue, threadLocal.get())\n        assertEquals(anotherMainValue, anotherThreadLocal.get())\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/coroutine/CoroutineThreadLocalContextContinuationInterceptorDemo.kt",
    "content": "package  com.alibaba.demo.coroutine\n\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.async\nimport kotlinx.coroutines.runBlocking\nimport kotlin.coroutines.AbstractCoroutineContextElement\nimport kotlin.coroutines.Continuation\nimport kotlin.coroutines.ContinuationInterceptor\nimport kotlin.coroutines.CoroutineContext\n\n/**\n * related material:\n *\n * - [Work with ThreadLocal-sensitive Components #119 - Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines/issues/119)\n *      - [How to use code that relies on ThreadLocal with Kotlin coroutines - Stack Overflow](https://stackoverflow.com/questions/46227462/how-to-use-code-that-relies-on-threadlocal-with-kotlin-coroutines/46227463)\n * - [README.md of Module kotlinx-coroutines-slf4j - Kotlin/kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines/blob/master/integration/kotlinx-coroutines-slf4j/README.md)\n */\nfun main(): Unit = runBlocking {\n    myThreadLocal.set(MyData(\"main value\"))\n\n    async(Dispatchers.IO) {\n        \"world(${myThreadLocal.get().data})\"\n    }.run {\n        println(\"Hello ${await()}!\")\n    }\n\n    async(MyThreadLocalContextContinuationInterceptor(myThreadLocal.get(), Dispatchers.IO)) {\n        \"world(${myThreadLocal.get().data})\"\n    }.run {\n        println(\"Hello ${await()}!\")\n    }\n}\n\nprivate val myThreadLocal = object : ThreadLocal<MyData>() {\n    override fun initialValue(): MyData {\n        return MyData(\"init value\")\n    }\n}\n\nprivate class MyThreadLocalContextContinuationInterceptor(\n        private var myData: MyData,\n        private val dispatcher: ContinuationInterceptor\n) : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {\n\n    override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =\n            dispatcher.interceptContinuation(Wrapper(continuation))\n\n    inner class Wrapper<T>(private val continuation: Continuation<T>) : Continuation<T> {\n\n        private inline fun wrap(block: () -> Unit) {\n            try {\n                myThreadLocal.set(myData)\n                block()\n            } finally {\n                myData = myThreadLocal.get()\n            }\n        }\n\n        override val context: CoroutineContext get() = continuation.context\n\n        override fun resumeWith(result: Result<T>) = wrap { continuation.resumeWith(result) }\n    }\n}\n\nprivate data class MyData(val data: String)\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/coroutine/ttl_intergration/TtlCoroutineContext.kt",
    "content": "package com.alibaba.demo.coroutine.ttl_intergration\n\nimport com.alibaba.ttl.TransmittableThreadLocal.Transmitter.*\nimport kotlinx.coroutines.ThreadContextElement\nimport kotlin.coroutines.CoroutineContext\nimport kotlin.coroutines.EmptyCoroutineContext\n\n/**\n * @see [kotlinx.coroutines.asContextElement]\n */\nfun ttlContext(): CoroutineContext =\n//        if (TtlAgent.isTtlAgentLoaded()) // FIXME Open the if when implement TtlAgent for koroutine\n//            EmptyCoroutineContext\n//        else\n            TtlElement()\n\n/**\n * @see [kotlinx.coroutines.internal.ThreadLocalElement]\n */\ninternal class TtlElement : ThreadContextElement<Any> {\n    companion object Key : CoroutineContext.Key<TtlElement>\n\n    override val key: CoroutineContext.Key<*> get() = Key\n\n    private var captured: Any =\n            capture()\n\n    override fun updateThreadContext(context: CoroutineContext): Any =\n            replay(captured)\n\n    override fun restoreThreadContext(context: CoroutineContext, oldState: Any) {\n        captured = capture() // FIXME This capture operation is a MUST, WHY? This operation is too expensive?!\n        restore(oldState)\n    }\n\n    // this method is overridden to perform value comparison (==) on key\n    override fun minusKey(key: CoroutineContext.Key<*>): CoroutineContext =\n            if (Key == key) EmptyCoroutineContext else this\n\n    // this method is overridden to perform value comparison (==) on key\n    override operator fun <E : CoroutineContext.Element> get(key: CoroutineContext.Key<E>): E? =\n            @Suppress(\"UNCHECKED_CAST\")\n            if (Key == key) this as E else null\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/coroutine/ttl_intergration/usage/TtlCoroutineContextDemo.kt",
    "content": "package com.alibaba.demo.coroutine.ttl_intergration.usage\n\nimport com.alibaba.demo.coroutine.ttl_intergration.ttlContext\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport kotlinx.coroutines.*\n\nprivate val threadLocal = TransmittableThreadLocal<String?>() // declare thread-local variable\n\n/**\n * [Thread-local data - Coroutine Context and Dispatchers - Kotlin Programming Language](https://kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html#thread-local-data)\n */\nfun main(): Unit = runBlocking {\n    val block: suspend CoroutineScope.() -> Unit = {\n        println(\"Launch start, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n        threadLocal.set(\"!reset!\")\n        println(\"After reset, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n        delay(5)\n        println(\"After yield, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n    }\n\n    threadLocal.set(\"main\")\n    println(\"======================\\nEmpty Coroutine Context\\n======================\")\n    println(\"Pre-main, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n    launch(block = block).join()\n    println(\"Post-main, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n\n    threadLocal.set(\"main\")\n    println()\n    println(\"======================\\nTTL Coroutine Context\\n======================\")\n    println(\"Pre-main, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n    launch(ttlContext(), block = block).join()\n    println(\"Post-main, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n\n    threadLocal.set(\"main\")\n    println()\n    println(\"======================\\nDispatchers.Default Coroutine Context\\n======================\")\n    println(\"Pre-main, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n    launch(Dispatchers.Default, block = block).join()\n    println(\"Post-main, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n\n    threadLocal.set(\"main\")\n    println()\n    println(\"======================\\nDispatchers.Default + TTL Coroutine Context\\n======================\")\n    println(\"Pre-main, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n    launch(Dispatchers.Default + ttlContext(), block = block).join()\n    println(\"Post-main, current thread: ${Thread.currentThread()}, thread local value: ${threadLocal.get()}\")\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/coroutine/ttl_intergration/usage/TtlCoroutineContextTest.kt",
    "content": "package com.alibaba.demo.coroutine.ttl_intergration.usage\n\nimport com.alibaba.demo.coroutine.ttl_intergration.ttlContext\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport io.kotest.core.spec.style.AnnotationSpec\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.runBlocking\nimport mu.KotlinLogging\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertNotEquals\n\nclass TtlCoroutineContextTest : AnnotationSpec() {\n    private val logger = KotlinLogging.logger {}\n\n    @Test\n    fun threadContextElement_passByValue(): Unit = runBlocking {\n        val mainValue = \"main-${System.currentTimeMillis()}\"\n        val testThread = Thread.currentThread()\n\n        // String ThreadLocal, String is immutable value, can only be passed by value\n        val threadLocal = TransmittableThreadLocal<String?>()\n        threadLocal.set(mainValue)\n        logger.info { \"test thread - thread local value: ${threadLocal.get()}\" }\n\n        val job = launch(Dispatchers.Default + ttlContext()) {\n            logger.info { \"launch thread - launch start, thread local value: ${threadLocal.get()}\" }\n            assertEquals(mainValue, threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay, thread local value: ${threadLocal.get()}\" }\n            assertEquals(mainValue, threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            val reset = \"job-reset-${threadLocal.get()}\"\n            threadLocal.set(reset)\n            assertEquals(reset, threadLocal.get())\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay set reset, thread local value: ${threadLocal.get()}\" }\n            assertEquals(reset, threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n        }\n        job.join()\n\n        logger.info { \"test thread - after launch, thread local value: ${threadLocal.get()}\" }\n        assertEquals(mainValue, threadLocal.get())\n    }\n\n    @Test\n    fun threadContextElement_passByReference(): Unit = runBlocking {\n        data class Reference(var data: Int = 42)\n\n        val mainValue = Reference()\n        val testThread = Thread.currentThread()\n\n        // Reference ThreadLocal, mutable value, pass by reference\n        val threadLocal = TransmittableThreadLocal<Reference>() // declare thread-local variable\n        threadLocal.set(mainValue)\n        logger.info { \"test thread - thread local value: ${threadLocal.get()}\" }\n\n        val job = launch(Dispatchers.Default + ttlContext()) {\n            logger.info { \"launch thread - launch start, thread local value: ${threadLocal.get()}\" }\n            assertEquals(mainValue, threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay, thread local value: ${threadLocal.get()}\" }\n            assertEquals(mainValue, threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            val reset = -42\n            threadLocal.get().data = reset\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay set reset, thread local value: ${threadLocal.get()}\" }\n            assertEquals(Reference(reset), threadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n        }\n        job.join()\n\n        logger.info { \"test thread - after launch thread local value: ${threadLocal.get()}\" }\n        assertEquals(mainValue, threadLocal.get())\n    }\n\n    @Test\n    fun twoThreadContextElement(): Unit = runBlocking {\n        val mainValue = \"main-a-${System.currentTimeMillis()}\"\n        val anotherMainValue = \"main-another-${System.currentTimeMillis()}\"\n        val testThread = Thread.currentThread()\n\n        val threadLocal = TransmittableThreadLocal<String?>() // declare thread-local variable\n        val anotherThreadLocal = TransmittableThreadLocal<String?>() // declare thread-local variable\n\n        threadLocal.set(mainValue)\n        anotherThreadLocal.set(anotherMainValue)\n        logger.info { \"test thread - thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n\n        launch(Dispatchers.Default + ttlContext()) {\n            logger.info { \"launch thread - launch start, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n            assertEquals(mainValue, threadLocal.get())\n            assertEquals(anotherMainValue, anotherThreadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n            assertEquals(mainValue, threadLocal.get())\n            assertEquals(anotherMainValue, anotherThreadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n\n            val resetA = \"job-reset-${threadLocal.get()}\"\n            threadLocal.set(resetA)\n            val resetAnother = \"job-reset-${anotherThreadLocal.get()}\"\n            anotherThreadLocal.set(resetAnother)\n            logger.info { \"launch thread - before delay set reset, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n\n            delay(5)\n\n            logger.info { \"launch thread - after delay set reset, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n            assertEquals(resetA, threadLocal.get())\n            assertEquals(resetAnother, anotherThreadLocal.get())\n            assertNotEquals(testThread, Thread.currentThread())\n        }.join()\n\n        logger.info { \"test thread - after launch2, thread local value: ${threadLocal.get()} | ${anotherThreadLocal.get()}\" }\n        assertEquals(mainValue, threadLocal.get())\n        assertEquals(anotherMainValue, anotherThreadLocal.get())\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/cow/CowDemo.kt",
    "content": "package com.alibaba.demo.cow\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.threadpool.TtlExecutors\nimport java.util.concurrent.Executors\nimport java.util.concurrent.TimeUnit\n\nfun main() {\n    val threadPool = Executors.newCachedThreadPool().let {\n        expandThreadPool(it)\n        TtlExecutors.getTtlExecutorService(it)\n    }!!\n\n    val traceContext = object : TransmittableThreadLocal<Trace>() {\n        override fun initialValue(): Trace = Trace(\"init\", Span(\"first\", 0))\n        override fun copy(parentValue: Trace): Trace = parentValue.copy() // shadow copy Trace, this is fast\n        override fun childValue(parentValue: Trace): Trace = parentValue.copy() // shadow copy Trace, this is fast\n\n        fun increaseSpan() {\n            get().run {\n                // COW the Span object in Trace\n                span = span.copy(id = \"${span.id} + PONG\", counter = span.counter + 1)\n            }\n        }\n\n        override fun toString(): String {\n            return \"${get()}[${super.toString()}]\"\n        }\n    }\n\n    fun printTtlInfo() {\n        println(\"${Thread.currentThread().name}: $traceContext\")\n    }\n\n    printTtlInfo()\n    threadPool.execute {\n        printTtlInfo()\n        traceContext.increaseSpan()\n        printTtlInfo()\n\n        threadPool.execute {\n            printTtlInfo()\n            traceContext.increaseSpan()\n            printTtlInfo()\n        }\n    }\n\n    Thread.sleep(100)\n    threadPool.shutdown()\n    threadPool.awaitTermination(1, TimeUnit.SECONDS)\n}\n\nprivate data class Trace(var name: String, var span: Span)\n\nprivate data class Span(val id: String, val counter: Int)\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/distributed_tracer/refcount/DistributedTracerUseDemo.kt",
    "content": "package com.alibaba.demo.distributed_tracer.refcount\n\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.threadpool.TtlExecutors\nimport java.lang.Thread.sleep\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.Executors\nimport java.util.concurrent.atomic.AtomicInteger\nimport kotlin.concurrent.thread\n\n/**\n * DistributedTracer(DT) use demo.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    rpcInvokeIn()\n\n    sleep(100)\n}\n\nprivate fun rpcInvokeIn() {\n    ////////////////////////////////////////////////\n    // DistributedTracer Framework Code\n    ////////////////////////////////////////////////\n\n    // Get Trace Id and Span Id from RPC Context\n    val traceId = \"traceId_XXXYYY\"\n    val baseSpanId = \"1.1\"\n    transferInfo.set(DtTransferInfo(traceId, baseSpanId))\n    traceId2LeafSpanIdInfo[traceId] = LeafSpanIdInfo()\n\n    increaseSpanIdRefCount()\n\n    ////////////////////////////////////////////////\n    // Biz Code\n    ////////////////////////////////////////////////\n    syncMethod()\n\n    ////////////////////////////////////////////////\n    // DistributedTracer Framework Code\n    ////////////////////////////////////////////////\n    decreaseSpanIdRefCount()\n}\n\nprivate val executorService = Executors.newFixedThreadPool(1) { r: Runnable ->\n    Thread(r, \"Executors\").apply { isDaemon = true }\n}.let { TtlExecutors.getTtlExecutorService(it) }!!\n\nprivate fun syncMethod() {\n    // async call by TTL Executor, Test OK!\n    executorService.submit { asyncMethod() }\n\n    // async call by new Thread\n    // FIXME Bug!! 没有 Increase/Decrease reference counter操作!\n    thread(name = \"Thread-by-new\") { syncMethod_ByNewThread() }\n\n    invokeServerWithRpc(\"server 1\")\n}\n\nprivate fun asyncMethod() {\n    invokeServerWithRpc(\"server 2\")\n}\n\nprivate fun syncMethod_ByNewThread() {\n    invokeServerWithRpc(\"server 3\")\n}\n\n\n// RPC invoke\nprivate fun invokeServerWithRpc(server: String) {\n    ////////////////////////////////////////////////\n    // DistributedTracer Framework Code\n    ////////////////////////////////////////////////\n\n    val leafSpanCurrent = increaseLeafSpanCurrentAndReturn()\n\n    // Set RpcContext\n    // Mocked, should use RPC util to get Rpc Context instead\n    val rpcContext = ConcurrentHashMap<String, String>()\n\n    rpcContext[\"traceId\"] = transferInfo.get()!!.traceId\n    rpcContext[\"spanId\"] = transferInfo.get()!!.baseSpanId + \".\" + leafSpanCurrent\n\n    // Do Rpc\n    // ...\n    System.out.printf(\"Do Rpc invocation to server %s with %s%n\", server, rpcContext)\n}\n\n//////////////////////////////////////////////////////////////////////////////////////////////////////////\n\ninternal class DtTransferInfo(val traceId: String, val baseSpanId: String)\n\ninternal class LeafSpanIdInfo(val current: AtomicInteger = AtomicInteger(1),\n                              val refCounter: AtomicInteger = AtomicInteger(0))\n\nprivate val transferInfo = object : TransmittableThreadLocal<DtTransferInfo>() {\n    /*\n@Override\nprotected DtTransferInfo childValue(DtTransferInfo parentValue) {\n    // **注意**：\n    // 新建线程时，从父线程继承值时，计数加1\n    // 对应线程结束时，没有回调以清理ThreadLocal中的Context！，Bug！！\n    // InheritableThreadLocal 没有提供 对应的拦截方法。。。 计数不配对了。。。\n    // 但是一个线程就一个Context没清，线程数有限，Context占用内存一般很小，可以接受。\n    increaseSpanIdRefCount();\n\n    return super.childValue(parentValue);\n}\n*/\n\n    override fun beforeExecute() {\n        super.beforeExecute()\n        increaseSpanIdRefCount()\n    }\n\n    override fun afterExecute() {\n        decreaseSpanIdRefCount()\n    }\n}\n\nprivate val traceId2LeafSpanIdInfo = ConcurrentHashMap<String, LeafSpanIdInfo>()\n\nprivate fun increaseSpanIdRefCount() {\n    val traceId = transferInfo.get().traceId\n    val refCounter = traceId2LeafSpanIdInfo[traceId]!!.refCounter.incrementAndGet()\n\n    System.out.printf(\"DEBUG: Increase reference counter(%s) for traceId %s in thread %s%n\", refCounter, traceId, Thread.currentThread().name)\n}\n\nprivate fun decreaseSpanIdRefCount() {\n    val traceId = transferInfo.get().traceId\n    val leafSpanIdInfo = traceId2LeafSpanIdInfo[traceId]\n\n    val refCounter = leafSpanIdInfo!!.refCounter.decrementAndGet()\n    System.out.printf(\"DEBUG: Decrease reference counter(%s) for traceId %s in thread %s%n\", refCounter, traceId, Thread.currentThread().name)\n\n    if (refCounter == 0) {\n        traceId2LeafSpanIdInfo.remove(traceId)\n\n        System.out.printf(\"DEBUG: Clear traceId2LeafSpanIdInfo for traceId %s in thread %s%n\", traceId, Thread.currentThread().name)\n    } else if (refCounter < 0) {\n        throw IllegalStateException(\"Leaf Span Id Info Reference counter has Bug!!\")\n    }\n}\n\nprivate fun increaseLeafSpanCurrentAndReturn(): Int {\n    val traceId = transferInfo.get()!!.traceId\n    return traceId2LeafSpanIdInfo[traceId]!!.current.getAndIncrement()\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/distributed_tracer/weakref/DistributedTracerUseDemo_WeakReferenceInsteadOfRefCounter.kt",
    "content": "package com.alibaba.demo.distributed_tracer.weakref\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.threadpool.TtlExecutors\nimport java.lang.Thread.sleep\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport java.util.concurrent.atomic.AtomicInteger\nimport java.util.concurrent.atomic.AtomicLong\nimport kotlin.concurrent.thread\n\nprivate val executorService: ExecutorService = Executors.newFixedThreadPool(1) { r: Runnable ->\n    Thread(r, \"Executors\").apply { isDaemon = true }\n}.let {\n    // ensure threads in pool is pre-created.\n    expandThreadPool(it)\n    TtlExecutors.getTtlExecutorService(it)\n}!!\n\n/**\n * DistributedTracer(DT) use demo.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    for (i in 0..42) {\n        rpcInvokeIn()\n    }\n\n    println(\"WARN: finished rpc invocation\")\n\n    // help to check GC status\n    sleep(200)\n    println(\"WARN: Call System.gc\")\n    System.gc()\n    println(\"WARN: Called System.gc\")\n    sleep(100)\n\n    println(\"Exit Main.\")\n}\n\n///////////////////////////////////////////////////////////////////////\n\nprivate fun rpcInvokeIn() {\n    ////////////////////////////////////////////////\n    // DistributedTracer Framework Code\n    ////////////////////////////////////////////////\n\n    // Get Trace Id and Span Id from RPC Context\n    val traceId = \"traceId_XXXYYY\" + traceIdCounter.getAndIncrement()\n    val baseSpanId = \"1.1\"\n\n    val leafSpanIdInfo = LeafSpanIdInfo()\n    transferInfo.set(DtTransferInfo(traceId, baseSpanId, leafSpanIdInfo))\n\n\n    ////////////////////////////////////////////////\n    // Biz Code\n    ////////////////////////////////////////////////\n    syncMethod()\n\n\n    ////////////////////////////////////////////////\n    // DistributedTracer Framework Code\n    ////////////////////////////////////////////////\n    System.out.printf(\"Finished Rpc call %s with span %s.%n\", traceId, leafSpanIdInfo)\n\n    // release context in ThreadLocal, avoid to be hold by thread, GC friendly.\n    transferInfo.remove()\n}\n\nprivate fun syncMethod() {\n    // async call by TTL Executor, Test OK!\n    executorService.submit { asyncMethod() }\n\n    // async call by new Thread\n    thread(name = \"Thread-by-new\") { syncMethod_ByNewThread() }\n\n    invokeServerWithRpc(\"server 1\")\n}\n\nprivate fun asyncMethod() {\n    sleep(3)\n    invokeServerWithRpc(\"server 2\")\n}\n\nprivate fun syncMethod_ByNewThread() {\n    sleep(2)\n    invokeServerWithRpc(\"server 3\")\n}\n\n\n// RPC invoke\nprivate fun invokeServerWithRpc(server: String) {\n    ////////////////////////////////////////////////\n    // DistributedTracer Framework Code\n    ////////////////////////////////////////////////\n\n    val leafSpanCurrent = increaseLeafSpanCurrentAndReturn()\n\n    // Set RpcContext\n    // Mocked, should use RPC util to get Rpc Context instead\n    val rpcContext = ConcurrentHashMap<String, String>()\n\n    rpcContext[\"traceId\"] = transferInfo.get()!!.traceId\n    rpcContext[\"spanId\"] = transferInfo.get()!!.baseSpanId + \".\" + leafSpanCurrent\n\n    // Do Rpc\n    // ...\n    System.out.printf(\"Do Rpc invocation to server %s with %s%n\", server, rpcContext)\n}\n\n///////////////////////////////////////////////////////////////////////\n// Span id management\n///////////////////////////////////////////////////////////////////////\n\nprivate val traceIdCounter = AtomicLong()\n\ninternal data class LeafSpanIdInfo(val current: AtomicInteger = AtomicInteger(1))\n\ninternal data class DtTransferInfo(val traceId: String, val baseSpanId: String, val leafSpanIdInfo: LeafSpanIdInfo) {\n    // Output GC operation\n    // How to implement finalize() in kotlin? - https://stackoverflow.com/questions/43784161\n    @Suppress(\"unused\", \"ProtectedInFinal\")\n    protected fun finalize() {\n        System.out.printf(\"DEBUG: gc DtTransferInfo traceId %s in thread %s: %s%n\",\n                traceId, Thread.currentThread().name, this)\n    }\n}\n\nprivate val transferInfo = TransmittableThreadLocal<DtTransferInfo>()\n\nprivate fun increaseLeafSpanCurrentAndReturn(): Int = transferInfo.get()!!.leafSpanIdInfo.current.getAndIncrement()\n\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/forkjoinpool/ForkJoinPoolDemo.kt",
    "content": "package com.alibaba.demo.forkjoinpool\n\nimport java.util.concurrent.ForkJoinPool\nimport java.util.concurrent.RecursiveTask\n\n/**\n * ForkJoinPool use demo.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val pool = ForkJoinPool.commonPool()\n\n    val result = pool.invoke(SumTask(1..1000))\n\n    println(\"computed result: $result\") // result is 500500\n}\n\ninternal class SumTask(private val numbers: IntRange, private val forkLevel: Int = 0) : RecursiveTask<Int>() {\n    override fun compute(): Int =\n        if (numbers.count() <= 16) {\n            println(String.format(\"direct compute %9s[%4s] at fork level %2s @ thread ${Thread.currentThread().name}\",\n                numbers, numbers.count(), forkLevel))\n\n            // compute directly\n            numbers.sum()\n        } else {\n            println(String.format(\"fork   compute %9s[%4s] at fork level %2s @ thread ${Thread.currentThread().name}\",\n                numbers, numbers.count(), forkLevel))\n\n            // split task\n            val middle = numbers.first + numbers.count() / 2\n            val nextForkLevel = forkLevel + 1\n            val taskLeft = SumTask(numbers.first until middle, nextForkLevel)\n            val taskRight = SumTask(middle..numbers.last, nextForkLevel)\n\n            // fork-join compute\n            taskLeft.fork()\n            taskRight.fork()\n            taskLeft.join() + taskRight.join()\n        }\n}\n\n/*\nOutput:\n\nfork   compute   1..1000[1000] at fork level  0 @ thread main\nfork   compute    1..500[ 500] at fork level  1 @ thread ForkJoinPool.commonPool-worker-19\nfork   compute 501..1000[ 500] at fork level  1 @ thread ForkJoinPool.commonPool-worker-5\nfork   compute  501..750[ 250] at fork level  2 @ thread ForkJoinPool.commonPool-worker-23\nfork   compute 751..1000[ 250] at fork level  2 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  251..500[ 250] at fork level  2 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  501..625[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute    1..250[ 250] at fork level  2 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  751..875[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute 876..1000[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  251..375[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  376..500[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  751..812[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute    1..125[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  376..437[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  876..937[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  626..750[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  376..406[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute     1..62[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  751..781[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  501..562[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  251..312[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  626..687[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  751..765[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  876..906[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  563..625[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  501..531[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute     1..31[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  876..890[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  376..390[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  563..593[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute     1..15[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  766..781[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  626..656[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  391..406[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  251..281[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute    16..31[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  563..577[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  891..906[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  407..437[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute    32..62[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  578..593[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  501..515[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  407..421[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  907..937[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  251..265[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  626..640[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  782..812[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  907..921[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  266..281[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  516..531[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  422..437[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  594..625[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  922..937[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute    32..46[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  532..562[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  282..312[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  782..796[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute    47..62[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  641..656[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  797..812[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute   63..125[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  282..296[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  532..546[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute 938..1000[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute    63..93[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  594..609[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  438..500[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  547..562[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  297..312[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  813..875[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  657..687[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  438..468[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  313..375[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  610..625[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute    63..77[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  438..452[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  938..968[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  344..375[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute    78..93[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  688..750[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute   94..125[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  938..952[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  688..718[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute   94..109[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  313..343[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  657..671[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  813..843[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  110..125[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  672..687[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-23\nfork   compute  719..750[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  813..827[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  688..702[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  953..968[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  453..468[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  344..359[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  703..718[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  828..843[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  719..734[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  126..250[ 125] at fork level  3 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  313..327[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  844..875[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  735..750[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  360..375[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  469..500[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute 969..1000[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  860..875[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  188..250[  63] at fork level  4 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  485..500[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-23\ndirect compute  969..984[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  844..859[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  126..187[  62] at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  328..343[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  219..250[  32] at fork level  5 @ thread ForkJoinPool.commonPool-worker-23\nfork   compute  188..218[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  126..156[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute 985..1000[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  469..484[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  188..202[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  219..234[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-23\ndirect compute  203..218[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  157..187[  31] at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  126..140[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  141..156[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  235..250[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-5\ndirect compute  172..187[  16] at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  157..171[  15] at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ncomputed result: 500500\n\n */\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/forkjoinpool/ParallelStreamDemo.kt",
    "content": "package com.alibaba.demo.forkjoinpool\n\nimport java.util.concurrent.ConcurrentSkipListSet\n\n/**\n * Parallel Stream use demo.\n *\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    println(\"availableProcessors: ${Runtime.getRuntime().availableProcessors()}\")\n\n    val threadNames: MutableSet<String> = ConcurrentSkipListSet()\n\n    (0..100).toList().stream().parallel().mapToInt {\n        threadNames.add(Thread.currentThread().name)\n        Thread.sleep(10)\n        println(\"map $it @ thread ${Thread.currentThread().name}\")\n\n        it\n    }.sum().let {\n        println(\"sum result: $it\")\n    }\n\n    println(threadNames.joinToString(\n        separator = \"\\n\\t\",\n        prefix = \"run threads(${threadNames.size}):\\n\\t\"\n    ))\n}\n\n/*\nOutput:\n\navailableProcessors: 12\nmap 78 @ thread ForkJoinPool.commonPool-worker-7\nmap 76 @ thread ForkJoinPool.commonPool-worker-21\nmap 91 @ thread ForkJoinPool.commonPool-worker-19\nmap 71 @ thread ForkJoinPool.commonPool-worker-13\nmap 65 @ thread main\nmap 97 @ thread ForkJoinPool.commonPool-worker-3\nmap 32 @ thread ForkJoinPool.commonPool-worker-5\nmap 15 @ thread ForkJoinPool.commonPool-worker-9\nmap 79 @ thread ForkJoinPool.commonPool-worker-17\nmap 82 @ thread ForkJoinPool.commonPool-worker-27\nmap 53 @ thread ForkJoinPool.commonPool-worker-31\nmap 57 @ thread ForkJoinPool.commonPool-worker-23\nmap 77 @ thread ForkJoinPool.commonPool-worker-21\nmap 86 @ thread ForkJoinPool.commonPool-worker-7\nmap 72 @ thread ForkJoinPool.commonPool-worker-13\nmap 92 @ thread ForkJoinPool.commonPool-worker-19\nmap 66 @ thread main\nmap 83 @ thread ForkJoinPool.commonPool-worker-27\nmap 58 @ thread ForkJoinPool.commonPool-worker-23\nmap 54 @ thread ForkJoinPool.commonPool-worker-31\nmap 98 @ thread ForkJoinPool.commonPool-worker-3\nmap 33 @ thread ForkJoinPool.commonPool-worker-5\nmap 16 @ thread ForkJoinPool.commonPool-worker-9\nmap 80 @ thread ForkJoinPool.commonPool-worker-17\nmap 75 @ thread ForkJoinPool.commonPool-worker-21\nmap 87 @ thread ForkJoinPool.commonPool-worker-7\nmap 93 @ thread ForkJoinPool.commonPool-worker-19\nmap 73 @ thread ForkJoinPool.commonPool-worker-13\nmap 67 @ thread main\nmap 81 @ thread ForkJoinPool.commonPool-worker-27\nmap 56 @ thread ForkJoinPool.commonPool-worker-23\nmap 55 @ thread ForkJoinPool.commonPool-worker-31\nmap 17 @ thread ForkJoinPool.commonPool-worker-9\nmap 99 @ thread ForkJoinPool.commonPool-worker-3\nmap 31 @ thread ForkJoinPool.commonPool-worker-5\nmap 84 @ thread ForkJoinPool.commonPool-worker-17\nmap 63 @ thread ForkJoinPool.commonPool-worker-19\nmap 89 @ thread ForkJoinPool.commonPool-worker-7\nmap 74 @ thread ForkJoinPool.commonPool-worker-13\nmap 95 @ thread ForkJoinPool.commonPool-worker-21\nmap 62 @ thread ForkJoinPool.commonPool-worker-27\nmap 60 @ thread ForkJoinPool.commonPool-worker-23\nmap 100 @ thread ForkJoinPool.commonPool-worker-3\nmap 51 @ thread ForkJoinPool.commonPool-worker-31\nmap 13 @ thread ForkJoinPool.commonPool-worker-9\nmap 35 @ thread ForkJoinPool.commonPool-worker-5\nmap 85 @ thread ForkJoinPool.commonPool-worker-17\nmap 64 @ thread ForkJoinPool.commonPool-worker-19\nmap 90 @ thread ForkJoinPool.commonPool-worker-7\nmap 69 @ thread ForkJoinPool.commonPool-worker-13\nmap 96 @ thread ForkJoinPool.commonPool-worker-21\nmap 94 @ thread ForkJoinPool.commonPool-worker-27\nmap 61 @ thread ForkJoinPool.commonPool-worker-23\nmap 14 @ thread ForkJoinPool.commonPool-worker-9\nmap 36 @ thread ForkJoinPool.commonPool-worker-5\nmap 44 @ thread ForkJoinPool.commonPool-worker-3\nmap 52 @ thread ForkJoinPool.commonPool-worker-31\nmap 88 @ thread ForkJoinPool.commonPool-worker-17\nmap 68 @ thread ForkJoinPool.commonPool-worker-19\nmap 40 @ thread ForkJoinPool.commonPool-worker-7\nmap 70 @ thread ForkJoinPool.commonPool-worker-13\nmap 48 @ thread ForkJoinPool.commonPool-worker-21\nmap 46 @ thread ForkJoinPool.commonPool-worker-27\nmap 59 @ thread ForkJoinPool.commonPool-worker-23\nmap 12 @ thread ForkJoinPool.commonPool-worker-9\nmap 34 @ thread ForkJoinPool.commonPool-worker-5\nmap 50 @ thread ForkJoinPool.commonPool-worker-31\nmap 38 @ thread ForkJoinPool.commonPool-worker-17\nmap 45 @ thread ForkJoinPool.commonPool-worker-3\nmap 41 @ thread ForkJoinPool.commonPool-worker-7\nmap 43 @ thread ForkJoinPool.commonPool-worker-19\nmap 28 @ thread ForkJoinPool.commonPool-worker-13\nmap 49 @ thread ForkJoinPool.commonPool-worker-21\nmap 47 @ thread ForkJoinPool.commonPool-worker-27\nmap 7 @ thread ForkJoinPool.commonPool-worker-23\nmap 21 @ thread ForkJoinPool.commonPool-worker-9\nmap 25 @ thread ForkJoinPool.commonPool-worker-3\nmap 3 @ thread ForkJoinPool.commonPool-worker-31\nmap 26 @ thread ForkJoinPool.commonPool-worker-5\nmap 39 @ thread ForkJoinPool.commonPool-worker-17\nmap 42 @ thread ForkJoinPool.commonPool-worker-7\nmap 19 @ thread ForkJoinPool.commonPool-worker-19\nmap 29 @ thread ForkJoinPool.commonPool-worker-13\nmap 1 @ thread ForkJoinPool.commonPool-worker-21\nmap 0 @ thread ForkJoinPool.commonPool-worker-27\nmap 8 @ thread ForkJoinPool.commonPool-worker-23\nmap 27 @ thread ForkJoinPool.commonPool-worker-5\nmap 22 @ thread ForkJoinPool.commonPool-worker-9\nmap 37 @ thread ForkJoinPool.commonPool-worker-17\nmap 4 @ thread ForkJoinPool.commonPool-worker-3\nmap 10 @ thread ForkJoinPool.commonPool-worker-31\nmap 20 @ thread ForkJoinPool.commonPool-worker-19\nmap 18 @ thread ForkJoinPool.commonPool-worker-7\nmap 30 @ thread ForkJoinPool.commonPool-worker-13\nmap 2 @ thread ForkJoinPool.commonPool-worker-21\nmap 23 @ thread ForkJoinPool.commonPool-worker-23\nmap 6 @ thread ForkJoinPool.commonPool-worker-27\nmap 9 @ thread ForkJoinPool.commonPool-worker-5\nmap 5 @ thread ForkJoinPool.commonPool-worker-3\nmap 11 @ thread ForkJoinPool.commonPool-worker-31\nmap 24 @ thread ForkJoinPool.commonPool-worker-23\nsum result: 5050\nrun threads(12):\n\tForkJoinPool.commonPool-worker-13\n\tForkJoinPool.commonPool-worker-17\n\tForkJoinPool.commonPool-worker-19\n\tForkJoinPool.commonPool-worker-21\n\tForkJoinPool.commonPool-worker-23\n\tForkJoinPool.commonPool-worker-27\n\tForkJoinPool.commonPool-worker-3\n\tForkJoinPool.commonPool-worker-31\n\tForkJoinPool.commonPool-worker-5\n\tForkJoinPool.commonPool-worker-7\n\tForkJoinPool.commonPool-worker-9\n\tmain\n\n */\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/scheduled_thread_pool_executor/ScheduledFutureTaskDemo.kt",
    "content": "package com.alibaba.demo.scheduled_thread_pool_executor\n\nimport java.util.concurrent.ScheduledThreadPoolExecutor\nimport java.util.concurrent.TimeUnit\n\n/**\n * ScheduledThreadPoolExecutor usage demo for Issue 148\n * https://github.com/alibaba/transmittable-thread-local/issues/148\n */\nfun main() {\n    val scheduledThreadPoolExecutor = ScheduledThreadPoolExecutor(10)\n\n    val task = Runnable { println(\"I'm a Runnable task, I'm working...\") }\n    val scheduledFuture = scheduledThreadPoolExecutor.scheduleWithFixedDelay(task, 500, 500, TimeUnit.MILLISECONDS)\n\n    Thread.sleep(2_000)\n\n    println(\"cancel\")\n    val cancelResult = scheduledFuture.cancel(false)\n    println(\"canceled: $cancelResult\")  // scheduled task cancel success!\n\n    Thread.sleep(2_000)\n    scheduledThreadPoolExecutor.shutdown()\n    println(\"Bye\")\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/session_cache/SessionCacheDemo.kt",
    "content": "package com.alibaba.demo.session_cache\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.TtlRunnable\nimport com.alibaba.ttl.threadpool.TtlExecutors\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport io.reactivex.Flowable\nimport io.reactivex.plugins.RxJavaPlugins\nimport io.reactivex.schedulers.Schedulers\nimport java.util.concurrent.*\n\n\nclass SessionCacheDemo : AnnotationSpec() {\n    @Test\n    fun invokeInThreadOfThreadPool() {\n        val bizService = BizService()\n        val printer: () -> Unit =\n            { System.out.printf(\"[%20s] cache: %s%n\", Thread.currentThread().name, bizService.getCacheItem()) }\n\n        executorService.submit(Callable {\n            bizService.getItemByCache().also { printer() }\n        }).get()\n\n        printer()\n\n        // here service invocation will use item cache\n        bizService.getItemByCache()\n        printer()\n    }\n\n    @Test\n    fun invokeInThreadOfRxJava() {\n        val bizService = BizService()\n        val printer: (Item) -> Unit =\n            { System.out.printf(\"[%30s] cache: %s%n\", Thread.currentThread().name, bizService.getCacheItem()) }\n\n        Flowable.just(bizService)\n            .observeOn(Schedulers.io())\n            .map(BizService::getItemByCache)\n            .doOnNext(printer)\n            .blockingSubscribe(printer)\n\n        // here service invocation will use item cache\n        bizService.getItemByCache()\n            .let(printer)\n    }\n\n    @BeforeAll\n    fun beforeAll() {\n        // expand Schedulers.io()\n        (0 until Runtime.getRuntime().availableProcessors() * 2)\n            .map {\n                FutureTask {\n                    Thread.sleep(10)\n                    it\n                }.apply { Schedulers.io().scheduleDirect(this) }\n            }\n            .forEach { it.get() }\n\n        // TTL integration for RxJava\n        RxJavaPlugins.setScheduleHandler(TtlRunnable::get)\n    }\n\n\n    @AfterAll\n    fun afterAll() {\n        executorService.shutdown()\n        // Fail to shut down thread pool\n        executorService.awaitTermination(1, TimeUnit.SECONDS).shouldBeTrue()\n    }\n\n    @After\n    fun tearDown() {\n        BizService.clearCache()\n    }\n\n    companion object {\n        private val executorService = Executors.newFixedThreadPool(3).let {\n            expandThreadPool(it)\n            // TTL integration for thread pool\n            TtlExecutors.getTtlExecutorService(it)!!\n        }\n    }\n}\n\n/**\n * Mock Service\n */\nprivate class BizService {\n    init {\n        // NOTE: AVOID cache object lazy init\n        getCache()\n    }\n\n    fun getItem(): Item = Item(ThreadLocalRandom.current().nextInt(0, 10_000))\n\n    /**\n     * get biz data, usually use spring cache. here is simple implementation\n     */\n    fun getItemByCache(): Item {\n        return getCache().computeIfAbsent(ONLY_KEY) { getItem() }\n    }\n\n    fun getCacheItem(): Item? = getCache()[ONLY_KEY]\n\n    companion object {\n        private const val ONLY_KEY = \"ONLY_KEY\"\n\n        private val cacheContext = object : TransmittableThreadLocal<ConcurrentMap<String, Item>>() {\n            // init cache\n            override fun initialValue(): ConcurrentMap<String, Item> = ConcurrentHashMap()\n        }\n\n        private fun getCache() = cacheContext.get()\n\n        fun clearCache() {\n            getCache().clear()\n        }\n    }\n}\n\n/**\n * Mock Cache Data\n */\nprivate data class Item(val id: Int)\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/timer/TimerTaskDemo.kt",
    "content": "package com.alibaba.demo.timer\n\nimport java.text.SimpleDateFormat\nimport java.util.*\n\n/**\n * @see [Java Timer TimerTask Example](https://www.journaldev.com/1050/java-timer-timertask-example)\n */\nfun main() {\n    val timerTask = MyTimerTask()\n\n    // running timer task as daemon thread\n    val timer = Timer(true)\n    timer.scheduleAtFixedRate(timerTask, 0, 300)\n    println(\"TimerTask scheduled\")\n\n    // cancel after sometime\n    Thread.sleep(1_000)\n    timer.cancel()\n    println(\"TimerTask cancelled\")\n\n    Thread.sleep(300)\n}\n\nclass MyTimerTask : TimerTask() {\n    override fun run() {\n        val format = SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss.SSS\")\n        println(\"Timer task started at: ${format.format(Date())}\")\n        Thread.sleep(200)\n        println(\"Timer task finished at: ${format.format(Date())}\")\n    }\n\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/ttl/CustomizedBlockingQueueWithTtlDemo.java",
    "content": "package com.alibaba.demo.ttl;\n\nimport com.alibaba.ttl.TtlRunnable;\nimport com.alibaba.ttl.threadpool.TtlExecutors;\n\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Simple demo code for issue\n * https://github.com/alibaba/transmittable-thread-local/issues/340\n */\npublic class CustomizedBlockingQueueWithTtlDemo {\n    public static void main(String[] args) throws Exception {\n        final MyBlockingQueue myBlockingQueue = new MyBlockingQueue();\n\n        final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(\n                1, 1, 1L, TimeUnit.SECONDS, myBlockingQueue);\n        final ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(threadPoolExecutor);\n\n        ttlExecutorService.execute(new MyTask(\"accept-1\"));\n        ttlExecutorService.execute(new MyTask(\"DISCARDED\"));\n        ttlExecutorService.execute(new MyTask(\"accept-2\"));\n\n        ttlExecutorService.shutdown();\n        if (!ttlExecutorService.awaitTermination(10, TimeUnit.SECONDS)) {\n            throw new IllegalStateException(\"Fail to shutdown executor service\");\n        }\n    }\n\n    private static class MyTask implements Runnable {\n        private final String msg;\n\n        private MyTask(String msg) {\n            this.msg = msg;\n        }\n\n        @Override\n        public void run() {\n            System.out.println(\"MyTask: \" + msg);\n        }\n    }\n\n    private static class MyBlockingQueue extends ArrayBlockingQueue<Runnable> {\n        public MyBlockingQueue() {\n            super(16);\n        }\n\n        @Override\n        public boolean offer(final Runnable runnable) {\n            // unwrap TtlRunnable first\n            final Runnable unwrap  = TtlRunnable.unwrap(runnable);\n\n            final MyTask myTask = (MyTask) unwrap;\n            if (myTask.msg.startsWith(\"accept-\")) {\n                // ignore result/return value of offer, BAD!!\n                //   does not follow the contract of method offer\n                // this is just a simple demo!\n                super.offer(runnable);\n            }\n\n            // always return true even if discard the task, BAD!!\n            //   does not follow the contract of method offer\n            // this is just a simple demo!\n            return true;\n        }\n\n        @Override\n        public void put(final Runnable runnable) throws InterruptedException {\n            // unwrap TtlRunnable first\n            final Runnable unwrap  = TtlRunnable.unwrap(runnable);\n\n            final MyTask myTask = (MyTask) unwrap;\n            // discard task if not satisfied, BAD!!\n            //   does not follow the contract of method put\n            // this is just a simple demo!\n            if (myTask.msg.startsWith(\"accept-\")) {\n                super.put(runnable);\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/ttl/SimpleDemo.kt",
    "content": "package com.alibaba.demo.ttl\n\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport kotlin.concurrent.thread\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val context = TransmittableThreadLocal<String>()\n\n    context.set(\"value-set-in-parent\")\n    println(\"[parent thread] set ${context.get()}\")\n\n    /////////////////////////////////////\n    // create sub-thread\n    /////////////////////////////////////\n    thread {\n        val value = context.get()\n        println(\"[child thread] get $value\")\n    }.join()\n\n    println(\"[parent thread] get ${context.get()}\")\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/ttl/TtlExecutorServiceWithPriorityBlockingQueueDemo.kt",
    "content": "package com.alibaba.demo.ttl\n\nimport com.alibaba.ttl.threadpool.TtlExecutors\nimport java.lang.Thread.sleep\nimport java.util.concurrent.BlockingQueue\nimport java.util.concurrent.PriorityBlockingQueue\nimport java.util.concurrent.ThreadPoolExecutor\nimport java.util.concurrent.TimeUnit\n\nfun main() {\n    demoSubmitComparableTaskToTtlExecutorServiceWithPriorityBlockingQueue()\n\n    demoSubmitOrderTaskToTtlExecutorServiceWithPriorityBlockingQueue()\n}\n\n/**\n * Demo for cooperation TTL executor(ThreadPoolExecutor) with PriorityBlockingQueue, for Comparable Runnable.\n *\n * if you use TTL Agent, no extra work(getTtlRunnableUnwrapComparatorForComparableRunnable) is need.\n * aka. rewriting PriorityBlockingQueue by TTL Agent automatically and transparently.\n */\nfun demoSubmitComparableTaskToTtlExecutorServiceWithPriorityBlockingQueue() {\n    val comparator: Comparator<Runnable> = TtlExecutors.getTtlRunnableUnwrapComparatorForComparableRunnable()\n\n    // explicit PriorityBlockingQueue Comparator argument\n    //   instead of default constructor PriorityBlockingQueue()\n    //\n    // aka. rewrite\n    //     val priorityBlockingQueue                   = PriorityBlockingQueue()\n    // to\n    val priorityBlockingQueue: BlockingQueue<Runnable> = PriorityBlockingQueue(11, comparator)\n\n    val threadPoolExecutor = ThreadPoolExecutor(1, 2, 1, TimeUnit.SECONDS, priorityBlockingQueue)\n    val ttlExecutorService = TtlExecutors.getTtlExecutorService(threadPoolExecutor)!!\n\n    ttlExecutorService.execute(BizComparableTask(0))\n    ttlExecutorService.execute(BizComparableTask(1))\n    ttlExecutorService.execute(BizComparableTask(2))\n    ttlExecutorService.execute(BizComparableTask(42))\n    ttlExecutorService.execute(BizComparableTask(9))\n    ttlExecutorService.execute(BizComparableTask(8))\n    ttlExecutorService.execute(BizComparableTask(7))\n\n    threadPoolExecutor.shutdown()\n    threadPoolExecutor.awaitTermination(5, TimeUnit.SECONDS)\n}\n\n\n/**\n * Demo for cooperation TTL executor(ThreadPoolExecutor) with PriorityBlockingQueue, for Runnable Comparator.\n *\n * if you use TTL Agent, no extra work(getTtlRunnableUnwrapComparator) is need.\n * aka. rewriting Comparator by TTL Agent automatically and transparently.\n */\nfun demoSubmitOrderTaskToTtlExecutorServiceWithPriorityBlockingQueue() {\n    val comparator: Comparator<Runnable> = compareBy { (it as BizOrderTask).order }\n    val ttlRunnableUnwrapComparator: Comparator<Runnable>? = TtlExecutors.getTtlRunnableUnwrapComparator(comparator)\n\n    // use TtlRunnableUnwrapComparator instead original comparator\n    //\n    // aka. rewrite\n    //     val priorityBlockingQueue                           = PriorityBlockingQueue(11, comparator)\n    // to\n    val priorityBlockingQueue: PriorityBlockingQueue<Runnable> = PriorityBlockingQueue(11, ttlRunnableUnwrapComparator)\n\n    val threadPoolExecutor = ThreadPoolExecutor(1, 2, 1, TimeUnit.SECONDS, priorityBlockingQueue)\n    val ttlExecutorService = TtlExecutors.getTtlExecutorService(threadPoolExecutor)!!\n\n    ttlExecutorService.execute(BizOrderTask(0))\n    ttlExecutorService.execute(BizOrderTask(1))\n    ttlExecutorService.execute(BizOrderTask(2))\n    ttlExecutorService.execute(BizOrderTask(42))\n    ttlExecutorService.execute(BizOrderTask(9))\n    ttlExecutorService.execute(BizOrderTask(8))\n    ttlExecutorService.execute(BizOrderTask(7))\n\n    threadPoolExecutor.shutdown()\n    threadPoolExecutor.awaitTermination(5, TimeUnit.SECONDS)\n}\n\n\nprivate data class BizComparableTask(val num: Int) : Runnable, Comparable<Runnable> {\n    override fun run() {\n        sleep(10)\n        println(\"run BizComparableTask $num\")\n    }\n\n    override fun compareTo(other: Runnable): Int = num - (other as BizComparableTask).num\n}\n\nprivate data class BizOrderTask(val order: Int) : Runnable {\n    override fun run() {\n        sleep(10)\n        println(\"run BizOrderTask $order\")\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/ttl/TtlExecutorWrapperDemo.kt",
    "content": "package com.alibaba.demo.ttl\n\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.threadpool.TtlExecutors\nimport java.util.concurrent.Callable\nimport java.util.concurrent.Executors\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val ttlExecutorService = Executors.newCachedThreadPool().let {\n        // return TTL wrapper from normal ExecutorService\n        TtlExecutors.getTtlExecutorService(it)\n    }!!\n    val context = TransmittableThreadLocal<String>()\n\n    context.set(\"value-set-in-parent\")\n    println(\"[parent thread] set ${context.get()}\")\n\n    /////////////////////////////////////\n    // Runnable\n    /////////////////////////////////////\n    val task = Runnable { println(\"[child thread] get ${context.get()} in Runnable\") }\n    ttlExecutorService.submit(task).get()\n\n    /////////////////////////////////////\n    // Callable\n    /////////////////////////////////////\n    val call = Callable {\n        println(\"[child thread] get ${context.get()} in Callable\")\n        42\n    }\n    ttlExecutorService.submit(call).get()\n\n    /////////////////////////////////////\n    // cleanup\n    /////////////////////////////////////\n    ttlExecutorService.shutdown()\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/ttl/TtlForkJoinTaskDemo.kt",
    "content": "package com.alibaba.demo.ttl\n\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.TtlRecursiveTask\nimport java.util.concurrent.ForkJoinPool\n\n\nval context = TransmittableThreadLocal<String>().apply {\n    set(\"value-set-in-parent\")\n    println(\"[parent thread] set ${get()} @ thread ${Thread.currentThread().name}\")\n}\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val pool = ForkJoinPool.commonPool()\n\n    val result = pool.invoke(SumTask(1..1000))\n\n    println(\"[parent thread] computed result: $result @ thread ${Thread.currentThread().name}\") // result is 500500\n}\n\nprivate class SumTask(private val numbers: IntRange, private val forkLevel: Int = 0) : TtlRecursiveTask<Int>() {\n    override fun compute(): Int =\n        if (numbers.count() <= 16) {\n            println(String.format(\"direct compute %9s[%4s] with context ${context.get()} at fork level %2s @ thread ${Thread.currentThread().name}\",\n                numbers, numbers.count(), forkLevel))\n\n            // compute directly\n            numbers.sum()\n        } else {\n            println(String.format(\"fork   compute %9s[%4s] with context ${context.get()} at fork level %2s @ thread ${Thread.currentThread().name}\",\n                numbers, numbers.count(), forkLevel))\n\n            // split task\n            val middle = numbers.first + numbers.count() / 2\n            val nextForkLevel = forkLevel + 1\n            val taskLeft = SumTask(numbers.first until middle, nextForkLevel)\n            val taskRight = SumTask(middle..numbers.last, nextForkLevel)\n\n            // fork-join compute\n            taskLeft.fork()\n            taskRight.fork()\n            taskLeft.join() + taskRight.join()\n        }\n}\n\n/*\nOutput:\n\n[parent thread] set value-set-in-parent @ thread main\nfork   compute   1..1000[1000] with context value-set-in-parent at fork level  0 @ thread main\nfork   compute 501..1000[ 500] with context value-set-in-parent at fork level  1 @ thread ForkJoinPool.commonPool-worker-5\nfork   compute    1..500[ 500] with context value-set-in-parent at fork level  1 @ thread ForkJoinPool.commonPool-worker-19\nfork   compute    1..250[ 250] with context value-set-in-parent at fork level  2 @ thread ForkJoinPool.commonPool-worker-23\nfork   compute  251..500[ 250] with context value-set-in-parent at fork level  2 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute 751..1000[ 250] with context value-set-in-parent at fork level  2 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  501..750[ 250] with context value-set-in-parent at fork level  2 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  126..250[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  251..375[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute 876..1000[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute    1..125[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  751..875[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  376..500[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  126..187[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  251..312[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute     1..62[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  501..625[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  751..812[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  876..937[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  376..437[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  126..156[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute     1..31[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  251..281[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  751..781[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  501..562[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  376..406[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute     1..15[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  876..906[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  251..265[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  126..140[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  751..765[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  501..531[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  376..390[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  266..281[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  141..156[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute    16..31[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  876..890[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  501..515[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  766..781[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  282..312[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  391..406[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  891..906[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute    32..62[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  157..187[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  782..812[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  516..531[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  282..296[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute    32..46[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  407..437[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  532..562[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  157..171[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  907..937[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute    47..62[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  532..546[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  297..312[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  782..796[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  907..921[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  172..187[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  407..421[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  313..375[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  797..812[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  547..562[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute   63..125[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  422..437[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  188..250[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  922..937[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  563..625[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  813..875[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  313..343[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  438..500[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute    63..93[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  563..593[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  313..327[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute    63..77[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute 938..1000[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  188..218[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  328..343[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute    78..93[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  563..577[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\nfork   compute  438..468[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  813..843[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute   94..125[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  344..375[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  188..202[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  438..452[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  938..968[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute   94..109[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  813..827[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  578..593[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  110..125[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  938..952[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  453..468[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  203..218[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-31\ndirect compute  344..359[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  594..625[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  828..843[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute  469..500[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  219..250[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  953..968[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  844..875[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  594..609[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  360..375[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  219..234[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  469..484[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  610..625[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  844..859[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\nfork   compute 969..1000[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute  485..500[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  235..250[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\nfork   compute  626..750[ 125] with context value-set-in-parent at fork level  3 @ thread ForkJoinPool.commonPool-worker-13\ndirect compute  860..875[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  969..984[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-7\ndirect compute 985..1000[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\nfork   compute  688..750[  63] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  626..687[  62] with context value-set-in-parent at fork level  4 @ thread ForkJoinPool.commonPool-worker-31\nfork   compute  688..718[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-9\nfork   compute  719..750[  32] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-7\nfork   compute  657..687[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-27\nfork   compute  626..656[  31] with context value-set-in-parent at fork level  5 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  688..702[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-9\ndirect compute  719..734[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-19\ndirect compute  703..718[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-21\ndirect compute  626..640[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-3\ndirect compute  672..687[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-17\ndirect compute  657..671[  15] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-27\ndirect compute  735..750[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-23\ndirect compute  641..656[  16] with context value-set-in-parent at fork level  6 @ thread ForkJoinPool.commonPool-worker-19\n[parent thread] computed result: 500500 @ thread main\n\n */\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/ttl/TtlWrapperDemo.kt",
    "content": "package com.alibaba.demo.ttl\n\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.TtlCallable\nimport com.alibaba.ttl.TtlRunnable\nimport java.util.concurrent.Callable\nimport java.util.concurrent.Executors\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val executorService = Executors.newCachedThreadPool()\n    val context = TransmittableThreadLocal<String>()\n\n    context.set(\"value-set-in-parent\")\n    println(\"[parent thread] set ${context.get()}\")\n\n    /////////////////////////////////////\n    // Runnable / TtlRunnable\n    /////////////////////////////////////\n    val task = Runnable { println(\"[child thread] get ${context.get()} in Runnable\") }\n    val ttlRunnable = TtlRunnable.get(task)!!\n\n    executorService.submit(ttlRunnable).get()\n\n    /////////////////////////////////////\n    // Callable / TtlCallable\n    /////////////////////////////////////\n    val call = Callable {\n        println(\"[child thread] get ${context.get()} in Callable\")\n        42\n    }\n    val ttlCallable = TtlCallable.get(call)!!\n\n    executorService.submit(ttlCallable).get()\n\n    /////////////////////////////////////\n    // cleanup\n    /////////////////////////////////////\n    executorService.shutdown()\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/ttl/TtlWrapperTypeInferenceProblemShowcase.java",
    "content": "package com.alibaba.demo.ttl;\n\nimport org.junit.Test;\n\nimport java.util.ArrayList;\nimport java.util.List;\n//import java.util.stream.Collectors;\n\n/**\n * @author huangfei1101 (fei.hf at alibaba-inc dot com)\n * @date 2021/12/30\n */\npublic class TtlWrapperTypeInferenceProblemShowcase {\n    @Test\n    public void wrapFunction() {\n        List<Integer> source = buildSourceList(10);\n\n        /*\n         * Try to call the function foo for each element in the list\n         * Because it is compatible with Java 6, the following code is commented\n         * The following line of code has a compilation error\n         */\n        //List<Integer> targetWithCompileError = source.parallelStream().map(TtlWrappers.wrap(i->foo(i))).collect(Collectors.toList());\n\n        /*\n         * The following line of code is correct\n         */\n        //List<Integer> target = source.parallelStream().map(TtlWrappers.wrapFunction(i->foo(i))).collect(Collectors.toList());\n    }\n\n    private int foo(int i) {\n        return i*10;\n    }\n\n    private List<Integer> buildSourceList(int length) {\n        List<Integer> l = new ArrayList<>();\n        for (int i = 0; i < length; ++i) {\n            l.add(i);\n        }\n        return l;\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/ttl/agent/AgentDemo.kt",
    "content": "@file:JvmName(\"AgentDemo\")\n\npackage com.alibaba.demo.ttl.agent\n\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val executorService = Executors.newFixedThreadPool(3)\n    expandThreadPool(executorService)\n\n    stringTransmittableThreadLocal.set(\"foo - main\")\n    personReferenceTransmittableThreadLocal.set(Person(\"jerry - reference\", 1))\n    personCopyTransmittableThreadLocal.set(Person(\"Tom - value\", 2))\n\n    printTtlInstancesInfo(\"Main - Before execution of thread pool\")\n\n    val submit = executorService.submit {\n        printTtlInstancesInfo(\"Thread Pool - enter\")\n        stringTransmittableThreadLocal.set(\"foo - modified in thread pool\")\n        personReferenceTransmittableThreadLocal.get().name = \"jerry - reference - modified in thread pool\"\n        personCopyTransmittableThreadLocal.get().name = \"Tom - value - modified in thread pool\"\n        printTtlInstancesInfo(\"Thread Pool - leave\")\n    }\n    submit.get()\n\n    printTtlInstancesInfo(\"Main - After execution of thread pool\")\n\n    executorService.shutdown()\n}\n\nprivate data class Person(var name: String = \"unnamed\", var age: Int = -1)\n\nprivate val stringTransmittableThreadLocal = TransmittableThreadLocal<String>()\n\nprivate val personReferenceTransmittableThreadLocal = object : TransmittableThreadLocal<Person>() {\n    override fun initialValue(): Person = Person()\n}\n\nprivate val personCopyTransmittableThreadLocal = object : TransmittableThreadLocal<Person>() {\n    override fun initialValue(): Person = Person()\n\n    override fun copy(parentValue: Person): Person = parentValue.copy() // copy value to child thread\n}\n\nprivate fun expandThreadPool(executor: ExecutorService) {\n    (0 until 3).map {\n        executor.submit { Thread.sleep(100) }\n    }.forEach {\n        it.get()\n    }\n}\n\nprivate fun printTtlInstancesInfo(msg: String) {\n    println(\"====================================================\")\n    println(msg)\n    println(\"====================================================\")\n    println(\"stringTransmittableThreadLocal: ${stringTransmittableThreadLocal.get()}\")\n    println(\"personReferenceTransmittableThreadLocal: ${personReferenceTransmittableThreadLocal.get()}\")\n    println(\"personCopyTransmittableThreadLocal: ${personCopyTransmittableThreadLocal.get()}\")\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/demo/ttl/agent/YourXxxAgent.java",
    "content": "package com.alibaba.demo.ttl.agent;\n\nimport com.alibaba.ttl.threadpool.agent.TtlAgent;\n\nimport java.lang.instrument.Instrumentation;\nimport java.util.logging.Logger;\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\npublic final class YourXxxAgent {\n    private static final Logger logger = Logger.getLogger(YourXxxAgent.class.getName());\n\n    public static void premain(String agentArgs, Instrumentation inst) throws Exception {\n        TtlAgent.premain(agentArgs, inst); // add TTL Transformer\n\n        // add your Transformer\n        // ...\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/it/README.md",
    "content": "Integration Test Cases\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/it/TimerAgentCheck.kt",
    "content": "package com.alibaba.it\n\nimport com.alibaba.*\nimport com.alibaba.ttl.testmodel.Task\nimport io.kotest.common.ExperimentalKotest\nimport io.kotest.core.spec.style.FunSpec\nimport io.kotest.core.test.TestScope\nimport io.kotest.engine.test.logging.info\nimport java.util.*\nimport java.util.concurrent.ConcurrentHashMap\n\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n * @see com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.TtlTimerTaskTransformlet\n */\n@ExperimentalKotest\nclass TimerAgentCheckTest : FunSpec({\n    fun TestScope.printHead(title: String) {\n        info { \"======================================\\n$title\\n======================================\" }\n    }\n\n    test(\"check\").config(enabled = hasTtlAgentRunWithEnableTimerTask()) {\n        val timer = Timer(true)\n\n        printHead(\"TimerAgentCheck\")\n\n        val ttlInstances = createParentTtlInstances(ConcurrentHashMap())\n\n        val tag = \"1\"\n        val task = Task(tag, ttlInstances)\n\n        val timerTask = object : TimerTask() {\n            override fun run() {\n                task.run()\n            }\n        }\n        timer.schedule(timerTask, 0)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n        // child Inheritable\n        assertChildTtlValues(tag, task.copied)\n        // child do not affect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n\n        printHead(\"TimerAgentCheck OK!\")\n    }\n})\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/perf/Utils.kt",
    "content": "package com.alibaba.perf\n\nimport java.util.*\n\nprivate val random = Random()\n\ninternal fun bytes2Hex(bytes: ByteArray): String {\n    val sb = StringBuilder(1024)\n    for (b in bytes) {\n        val s = Integer.toHexString(b.toInt() and 0xFF)\n        sb.append(if (s.length == 1) \"0$s\" else s)\n    }\n    return sb.toString()\n}\n\ninternal fun getRandomBytes(): ByteArray {\n    val bytes = ByteArray(1024)\n    random.nextBytes(bytes)\n    return bytes\n}\n\ninternal fun getRandomString(): String {\n    return bytes2Hex(getRandomBytes())\n}\n\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/perf/memoryleak/NoMemoryLeak_ThreadLocal_NoRemove.kt",
    "content": "@file:JvmName(\"NoMemoryLeak_ThreadLocal_NoRemove\")\n\npackage com.alibaba.perf.memoryleak\n\nimport com.alibaba.perf.getRandomString\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    var counter: Long = 0\n    while (true) {\n        val threadLocal = ThreadLocal<String>()\n        threadLocal.set(getRandomString())\n\n        if (counter % 1000 == 0L)\n            System.out.printf(\"%05dK%n\", counter / 1000)\n        counter++\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/perf/memoryleak/NoMemoryLeak_TransmittableThreadLocal_NoRemove.kt",
    "content": "@file:JvmName(\"NoMemoryLeak_TransmittableThreadLocal_NoRemove\")\n\npackage com.alibaba.perf.memoryleak\n\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.perf.getRandomString\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    var counter: Long = 0\n    while (true) {\n        val threadLocal = TransmittableThreadLocal<String>()\n        threadLocal.set(getRandomString())\n\n        if (counter % 1000 == 0L)\n            System.out.printf(\"%05dK%n\", counter / 1000)\n        counter++\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/perf/tps/CreateThreadLocalInstanceTps.kt",
    "content": "@file:JvmName(\"CreateThreadLocalInstanceTps\")\n\npackage com.alibaba.perf.tps\n\nimport com.alibaba.perf.getRandomString\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val tpsCounter = TpsCounter(2)\n\n    tpsCounter.setAction {\n        val threadLocal = ThreadLocal<String>()\n        threadLocal.set(getRandomString())\n    }\n\n    while (true) {\n        val start = tpsCounter.count\n        Thread.sleep(1000)\n        System.out.printf(\"tps: %,d\\n\", tpsCounter.count - start)\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/perf/tps/CreateTransmittableThreadLocalInstanceTps.kt",
    "content": "@file:JvmName(\"CreateTransmittableThreadLocalInstanceTps\")\n\npackage com.alibaba.perf.tps\n\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.perf.getRandomString\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nfun main() {\n    val tpsCounter = TpsCounter(2)\n\n    tpsCounter.setAction {\n        val threadLocal = TransmittableThreadLocal<String>()\n        threadLocal.set(getRandomString())\n    }\n\n    while (true) {\n        val start = tpsCounter.count\n        Thread.sleep(1000)\n        System.out.printf(\"tps: %d\\n\", tpsCounter.count - start)\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/perf/tps/TpsCounter.kt",
    "content": "package com.alibaba.perf.tps\n\nimport org.junit.Assert.assertTrue\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.atomic.AtomicLong\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass TpsCounter internal constructor(private val threadCount: Int) {\n    private val executorService: ExecutorService = Executors.newFixedThreadPool(threadCount)\n\n    private val counter = AtomicLong()\n\n    @Volatile\n    private var stopped = false\n\n    val count: Long\n        get() = counter.get()\n\n    internal fun setAction(runnable: Runnable) {\n        val r = {\n            while (!stopped) {\n                runnable.run()\n                counter.incrementAndGet()\n            }\n        }\n        for (i in 0 until threadCount) {\n            executorService.execute(r)\n        }\n    }\n\n    fun stop() {\n        stopped = true\n\n        executorService.shutdown()\n        assertTrue(\"Fail to shutdown thread pool\", executorService.awaitTermination(1, TimeUnit.SECONDS))\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/third_part_lib_test/ExecutorsTest.kt",
    "content": "package com.alibaba.third_part_lib_test\n\nimport io.kotest.core.spec.style.AnnotationSpec\nimport org.junit.Assert.assertFalse\nimport org.junit.Assert.assertTrue\nimport java.util.concurrent.Executors\nimport java.util.concurrent.ThreadPoolExecutor\nimport java.util.concurrent.TimeUnit\n\n\nclass ExecutorsTest : AnnotationSpec() {\n    @Test\n    fun test_remove_of_ThreadPoolExecutor() {\n        val size = 2\n        val threadPool = Executors.newFixedThreadPool(size) as ThreadPoolExecutor\n\n        val futures = (0..size * 2).map {\n            threadPool.submit {\n                Thread.sleep(10)\n            }\n        }\n\n        Runnable {\n            println(\"Task should be removed!\")\n        }.let {\n            threadPool.execute(it)\n            assertTrue(threadPool.remove(it))\n            assertFalse(threadPool.remove(it))\n        }\n\n        // wait sleep task finished.\n        futures.forEach { it.get() }\n\n        threadPool.shutdown()\n        assertTrue(\"Fail to shutdown thread pool\", threadPool.awaitTermination(1, TimeUnit.SECONDS))\n    }\n}\n\n\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/third_part_lib_test/ForkJoinPoolTest.kt",
    "content": "package com.alibaba.third_part_lib_test\n\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport io.kotest.matchers.shouldBe\nimport java.util.concurrent.ForkJoinPool\nimport java.util.concurrent.RecursiveTask\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.atomic.AtomicInteger\n\nclass ForkJoinPoolTest : AnnotationSpec() {\n\n    @Test\n    fun test_sameTaskDirectReturn_onlyExec1Time_ifHaveRun() {\n        val pool = ForkJoinPool()\n\n        val numbers = 1L..100L\n        val sumTask = SumTask(numbers)\n\n        // same task instance run 10 times\n        for (i in 0..9) {\n            pool.invoke(sumTask) shouldBe numbers.sum()\n        }\n\n        sumTask.execCounter.get() shouldBe 1\n\n        // close\n        pool.shutdown()\n\n        // Fail to shut down thread pool\n        pool.awaitTermination(1, TimeUnit.SECONDS).shouldBeTrue()\n    }\n\n    private class SumTask(private val numbers: LongRange) : RecursiveTask<Long>() {\n        val execCounter = AtomicInteger(0)\n\n        override fun compute(): Long {\n            execCounter.incrementAndGet()\n\n            return if (numbers.count() <= 16) {\n                // compute directly\n                numbers.sum()\n            } else {\n                // split task\n                val middle = numbers.first + numbers.count() / 2\n\n                val taskLeft = SumTask(numbers.first until middle)\n                val taskRight = SumTask(middle..numbers.last)\n\n                taskLeft.fork()\n                taskRight.fork()\n                taskLeft.join() + taskRight.join()\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/third_part_lib_test/JavassistTest.kt",
    "content": "package com.alibaba.third_part_lib_test\n\nimport com.alibaba.noTtlAgentRun\nimport io.kotest.assertions.fail\nimport io.kotest.assertions.throwables.shouldThrow\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.core.test.config.TestCaseConfig\nimport io.kotest.matchers.shouldBe\nimport io.kotest.matchers.string.shouldContain\nimport javassist.ClassPool\nimport javassist.CtClass\n\n/**\n * [simplify the try-finally code gen by javassist, do not need copy method #115](https://github.com/alibaba/transmittable-thread-local/issues/115)\n */\nclass JavassistTest : AnnotationSpec() {\n    /**\n     * when run unit test under TTL agent,\n     * javassist is repackaged and excluded.\n     *\n     * skip this test case.\n     */\n    @Suppress(\"OVERRIDE_DEPRECATION\")\n    override fun defaultTestCaseConfig(): TestCaseConfig = TestCaseConfig(enabled = noTtlAgentRun())\n\n    @Test\n    fun insertAfter_as_finally() {\n        val classPool = ClassPool(true)\n        val ctClass = classPool.getCtClass(\"com.alibaba.third_part_lib_test.DemoRunnable\")\n        // To execute it when an exception is thrown, the second parameter asFinally to insertAfter() must be true.\n        ctClass.getDeclaredMethod(\"run\", arrayOf()).insertAfter(\"value = 42;\", true)\n\n        val instance = ctClass.toClass().getDeclaredConstructor().newInstance()\n\n        (instance as Supplier).get() shouldBe 0\n\n        (instance as Runnable).let {\n            try {\n                it.run()\n                fail(\"must not run to here\")\n            } catch (e: RuntimeException) {\n                e.message shouldBe \"Intended\"\n            }\n        }\n\n        (instance as Supplier).get() shouldBe 42\n    }\n\n    /**\n     * more info see\n     * - [Bad Bytecode when trying access localVariable using insertAfter and asFinally = true](https://issues.jboss.org/browse/JASSIST-232?_sscc=t)\n     * - Javadoc of [javassist.CtBehavior.addLocalVariable]:\n     * If the second parameter asFinally to insertAfter() is true, the declared local variable is not visible from the code inserted by insertAfter().\n     */\n    @Test\n    fun insertAfter_as_finally_fail_with_local_var() {\n        val classPool = ClassPool(true)\n        val ctClass = classPool.getCtClass(\"com.alibaba.third_part_lib_test.DemoRunnable2\")\n        // To execute it when an exception is thrown, the second parameter asFinally to insertAfter() must be true.\n        ctClass.getDeclaredMethod(\"run\", arrayOf()).apply {\n            addLocalVariable(\"var\", CtClass.intType)\n            insertBefore(\"var = 2;\")\n            insertAfter(\"value = 40 + var;\", true)\n        }\n\n\n        shouldThrow<VerifyError> {\n            (ctClass.toClass().getDeclaredConstructor().newInstance() as Runnable).run()\n        }.message shouldContain \"Bad local variable type\"\n    }\n}\n\nprivate interface Supplier {\n    fun get(): Int\n}\n\n@Suppress(\"unused\")\nprivate class DemoRunnable : Runnable, Supplier {\n    @Volatile\n    private var value = 0\n\n    override fun get(): Int = value\n\n    override fun run() {\n        throw RuntimeException(\"Intended\")\n    }\n}\n\n@Suppress(\"unused\")\nprivate class DemoRunnable2 : Runnable, Supplier {\n    @Volatile\n    private var value = 0\n\n    override fun get(): Int = value\n\n    override fun run() {}\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/InheritableTest.kt",
    "content": "package com.alibaba.ttl\n\nimport com.alibaba.hasTtlAgentRunWithDisableInheritableForThreadPool\nimport com.alibaba.ttl.threadpool.TtlExecutors\nimport com.alibaba.ttl.threadpool.TtlForkJoinPoolHelper\nimport com.alibaba.ttl.threadpool.agent.TtlAgent\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport java.util.*\nimport java.util.concurrent.Callable\nimport java.util.concurrent.Executors\nimport java.util.concurrent.ForkJoinPool\nimport java.util.concurrent.ThreadPoolExecutor\n\nprivate const val hello = \"hello\"\nprivate val defaultValue = \"${Date()} ${Math.random()}\"\n\nclass InheritableTest : AnnotationSpec() {\n\n    // ===================================================\n    // Executors\n    // ===================================================\n\n    @Test\n    fun inheritable_Executors() {\n        val threadPool = Executors.newCachedThreadPool()\n        try {\n            val ttl = TransmittableThreadLocal<String?>()\n            ttl.set(hello)\n\n            val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!\n\n            // get \"hello\" value is transmitted by InheritableThreadLocal function!\n            // NOTE: Executors.newCachedThreadPool create thread lazily\n\n            threadPool.submit(callable).get() shouldBe hello\n\n            // current thread's TTL must be existed\n            ttl.get() shouldBe hello\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    @Test\n    fun disableInheritable_Executors_DisableInheritableThreadFactory() {\n        val threadPool = Executors.newCachedThreadPool(TtlExecutors.getDefaultDisableInheritableThreadFactory())\n        try {\n            val ttl = TransmittableThreadLocal<String?>()\n            ttl.set(hello)\n\n            val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                // when ttl agent is loaded, Callable is wrapped when submitted,\n                // so here value is \"hello\" transmitted by TtlCallable wrapper\n                threadPool.submit(callable).get() shouldBe hello\n            } else {\n                // when ttl agent is not loaded: null\n                threadPool.submit(callable).get().shouldBeNull()\n            }\n\n\n            // current thread's TTL must be existed when using DisableInheritableThreadFactory\n            ttl.get() shouldBe hello\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    @Test\n    fun disableInheritable_Executors_TtlDisableInheritableWithInitialValue() {\n        val threadPool = Executors.newCachedThreadPool()\n        try {\n            val ttl = object : TransmittableThreadLocal<String?>() {\n                override fun childValue(parentValue: String?): String? = initialValue()\n            }\n            ttl.set(hello)\n\n            val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!\n\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                // when ttl agent is loaded, Callable is wrapped when submitted,\n                // so here value is \"hello\" transmitted by TtlCallable wrapper\n                threadPool.submit(callable).get() shouldBe hello\n            } else {\n                // when ttl agent is not loaded: null\n                threadPool.submit(callable).get().shouldBeNull()\n            }\n\n            // current thread's TTL must be existed\n            ttl.get() shouldBe hello\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    @Test\n    fun disableInheritable_Executors_TtlDefaultValue_TtlDisableInheritableWithInitialValue() {\n        val threadPool = Executors.newCachedThreadPool()\n        try {\n            val ttl = object : TransmittableThreadLocal<String>() {\n                override fun initialValue(): String = defaultValue\n                override fun childValue(parentValue: String): String = initialValue()\n            }\n            ttl.set(hello)\n\n            val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!\n\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                // when ttl agent is loaded, Callable is wrapped when submitted,\n                // so here value is \"hello\" transmitted by TtlCallable wrapper\n                threadPool.submit(callable).get() shouldBe hello\n            } else {\n                // when ttl agent is not loaded: defaultValue\n                threadPool.submit(callable).get() shouldBe defaultValue\n            }\n\n            // current thread's TTL must be existed when using DisableInheritableThreadFactory\n            ttl.get() shouldBe hello\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    @Test\n    fun disableInheritable_Executors_TtlDefaultValue_DisableInheritableThreadFactory_TtlWithInitialValue() {\n        val threadPool = Executors.newCachedThreadPool(TtlExecutors.getDefaultDisableInheritableThreadFactory())\n        try {\n            val ttl = object : TransmittableThreadLocal<String>() {\n                override fun initialValue(): String = defaultValue\n                override fun childValue(parentValue: String): String = initialValue()\n            }\n            ttl.set(hello)\n\n            val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                // when ttl agent is loaded, Callable is wrapped when submitted,\n                // so here value is \"hello\" transmitted by TtlCallable wrapper\n                threadPool.submit(callable).get() shouldBe hello\n            } else {\n                // when ttl agent is not loaded: defaultValue\n                threadPool.submit(callable).get() shouldBe defaultValue\n            }\n\n            // current thread's TTL must be existed when using DisableInheritableThreadFactory\n            ttl.get() shouldBe hello\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    @Test\n    fun disableInheritable_Executors_ByAgent() {\n        val threadPool = Executors.newCachedThreadPool() as ThreadPoolExecutor\n        try {\n            TtlExecutors.isDisableInheritableThreadFactory(threadPool.threadFactory) shouldBe\n                    hasTtlAgentRunWithDisableInheritableForThreadPool()\n\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    // ===================================================\n    // ForkJoinPool\n    // ===================================================\n\n    @Test\n    fun inheritable_ForkJoinPool() {\n        val threadPool = ForkJoinPool(4)\n        try {\n            val ttl = TransmittableThreadLocal<String?>()\n            ttl.set(hello)\n\n            val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!\n\n            // get \"hello\" value is transmitted by InheritableThreadLocal function!\n            // NOTE: Executors.newCachedThreadPool create thread lazily\n            threadPool.submit(callable).get() shouldBe hello\n\n            // current thread's TTL must be existed\n            ttl.get() shouldBe hello\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    @Test\n    fun disableInheritable_ForkJoinPool_DisableInheritableForkJoinWorkerThreadFactory() {\n        val threadPool = ForkJoinPool(\n            4,\n            TtlForkJoinPoolHelper.getDefaultDisableInheritableForkJoinWorkerThreadFactory(),\n            null,\n            false\n        )\n        try {\n            val ttl = TransmittableThreadLocal<String?>()\n            ttl.set(hello)\n\n            val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                // when ttl agent is loaded, Callable is wrapped when submitted,\n                // so here value is \"hello\" transmitted by TtlCallable wrapper\n                threadPool.submit(callable).get() shouldBe hello\n            } else {\n                // when ttl agent is not loaded: null\n                threadPool.submit(callable).get().shouldBeNull()\n            }\n\n            // current thread's TTL must be existed when using DisableInheritableForkJoinWorkerThreadFactory\n            ttl.get() shouldBe hello\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    @Test\n    fun disableInheritable_ForkJoinPool_TtlDisableInheritableWithInitialValue() {\n        val threadPool = ForkJoinPool(4)\n        try {\n            val ttl = object : TransmittableThreadLocal<String?>() {\n                override fun childValue(parentValue: String?): String? = initialValue()\n            }\n            ttl.set(hello)\n\n            val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                // when ttl agent is loaded, Callable is wrapped when submitted,\n                // so here value is \"hello\" transmitted by TtlCallable wrapper\n                threadPool.submit(callable).get() shouldBe hello\n            } else {\n                // when ttl agent is not loaded: null\n                threadPool.submit(callable).get().shouldBeNull()\n            }\n\n            // current thread's TTL must be existed\n            ttl.get() shouldBe hello\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    @Test\n    fun disableInheritable_ForkJoinPool_TtlDefaultValue_TtlDisableInheritableWithInitialValue() {\n        val threadPool = ForkJoinPool(4)\n        try {\n            val ttl = object : TransmittableThreadLocal<String>() {\n                override fun initialValue(): String = defaultValue\n                override fun childValue(parentValue: String): String = initialValue()\n            }\n            ttl.set(hello)\n\n            val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!\n            if (TtlAgent.isTtlAgentLoaded()) {\n                // when ttl agent is loaded, Callable is wrapped when submitted,\n                // so here value is \"hello\" transmitted by TtlCallable wrapper\n                threadPool.submit(callable).get() shouldBe hello\n            } else {\n                // when ttl agent is not loaded: null\n                threadPool.submit(callable).get() shouldBe defaultValue\n            }\n\n            // current thread's TTL must be existed\n            ttl.get() shouldBe hello\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    @Test\n    fun disableInheritable_ForkJoinPool_TtlDefaultValue_DisableInheritableForkJoinWorkerThreadFactory_TtlWithInitialValue() {\n        val threadPool = ForkJoinPool(\n            4,\n            TtlForkJoinPoolHelper.getDefaultDisableInheritableForkJoinWorkerThreadFactory(),\n            null,\n            false\n        )\n        try {\n            val ttl = object : TransmittableThreadLocal<String>() {\n                override fun initialValue(): String = defaultValue\n                override fun childValue(parentValue: String): String = initialValue()\n            }\n            ttl.set(hello)\n\n            val callable = Callable { ttl.get() } // NO TtlWrapper(TtlCallable) here!!\n\n            if (TtlAgent.isTtlAgentLoaded()) {\n                // when ttl agent is loaded, Callable is wrapped when submitted,\n                // so here value is \"hello\" transmitted by TtlCallable wrapper\n                threadPool.submit(callable).get() shouldBe hello\n            } else {\n                // when ttl agent is not loaded: null\n                threadPool.submit(callable).get() shouldBe defaultValue\n            }\n\n            // current thread's TTL must be existed when using DisableInheritableForkJoinWorkerThreadFactory\n            ttl.get() shouldBe hello\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n    @Test\n    fun disableInheritable_ForkJoinPool_ByAgent() {\n        val threadPool = ForkJoinPool(4)\n        try {\n            TtlForkJoinPoolHelper.isDisableInheritableForkJoinWorkerThreadFactory(threadPool.factory) shouldBe\n                    hasTtlAgentRunWithDisableInheritableForThreadPool()\n        } finally {\n            threadPool.shutdown()\n        }\n    }\n\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/README.md",
    "content": "测试说明\n=====================\n\n测试过程创建的`TTL`的Key约定：\n\n- 父\n    - parent-created-unmodified-in-child，子中没有去修改\n    - parent-created-modified-in-child，子中会修改\n    - parent-created-after-create-TtlTask，在创建`TtlRunnable`/`TtlCallable`之后，在父中创建的`value`。\n- 子\n    - child-created，在子中创建的`value`\n\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/TtlCallableTest.kt",
    "content": "package com.alibaba.ttl\n\nimport com.alibaba.*\nimport com.alibaba.ttl.testmodel.Call\nimport io.kotest.assertions.throwables.shouldThrow\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.collections.shouldHaveSize\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.string.shouldContain\nimport io.kotest.matchers.types.shouldBeInstanceOf\nimport org.junit.Assert.*\nimport java.util.concurrent.Callable\nimport java.util.concurrent.ExecutionException\nimport java.util.concurrent.Executors\nimport java.util.concurrent.TimeUnit\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass TtlCallableTest : AnnotationSpec() {\n    @Test\n    fun test_TtlCallable_runInCurrentThread() {\n        val ttlInstances = createParentTtlInstances()\n\n        val call = Call(\"1\", ttlInstances)\n\n\n        val ttlCallable = TtlCallable.get(call)!!\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        // run in the *current* thread\n        assertEquals(\"ok\", ttlCallable.call())\n\n\n        // child Inheritable\n        assertChildTtlValues(\"1\", call.copied)\n\n        // child do not effect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n\n    @Test\n    fun test_TtlCallable_asyncRunByExecutorService() {\n        val ttlInstances = createParentTtlInstances()\n\n        val call = Call(\"1\", ttlInstances)\n        val ttlCallable = if (noTtlAgentRun()) TtlCallable.get(call) else call\n\n        if (noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n        val future = executorService.submit(ttlCallable)\n        if (!noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n\n        assertEquals(\"ok\", future.get())\n\n\n        // child Inheritable\n        assertChildTtlValues(\"1\", call.copied)\n\n        // child do not effect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n\n    @Test\n    fun test_remove_sameAsNotSet() {\n        val ttlInstances = createParentTtlInstances()\n\n\n        // add and remove !!\n        newTtlInstanceAndPut(\"add and removed!\", ttlInstances).remove()\n\n        val call = Call(\"1\", ttlInstances)\n        val ttlCallable = if (noTtlAgentRun()) TtlCallable.get(call) else call\n\n\n        if (noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n        val future = executorService.submit(ttlCallable)\n        if (!noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n\n        assertEquals(\"ok\", future.get())\n\n\n        // child Inheritable\n        assertChildTtlValues(\"1\", call.copied)\n\n        // child do not affect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n\n    @Test\n    fun test_releaseTtlValueReferenceAfterCall() {\n        val ttlInstances = createParentTtlInstances()\n\n        val call = Call(\"1\", ttlInstances)\n        val ttlCallable = TtlCallable.get(call, true)!!\n        assertSame(call, ttlCallable.callable)\n\n        assertEquals(\"ok\", executorService.submit(ttlCallable).get())\n\n\n        val exception = shouldThrow<ExecutionException> {\n            executorService.submit(ttlCallable).get()\n        }\n        exception.cause.shouldBeInstanceOf<IllegalStateException>()\n        exception.message shouldContain \"TTL value reference is released after call!\"\n    }\n\n    @Test\n    fun test_get_same() {\n        val call = Call(\"1\")\n        val ttlCallable = TtlCallable.get(call)!!\n        assertSame(call, ttlCallable.callable)\n    }\n\n    @Test\n    fun test_get_idempotent() {\n        val call = TtlCallable.get(Call(\"1\"))\n\n        shouldThrow<java.lang.IllegalStateException> {\n            TtlCallable.get(call)\n        }.message shouldContain \"Already TtlCallable\"\n    }\n\n    @Test\n    fun test_get_nullInput() {\n        TtlCallable.get<Any>(null).shouldBeNull()\n    }\n\n    @Test\n    fun test_gets() {\n        val call1 = Call(\"1\")\n        val call2 = Call(\"2\")\n        val call3 = Call(\"3\")\n\n        val callList = TtlCallable.gets(\n            listOf<Callable<String>?>(call1, call2, null, call3)\n        )\n\n        callList.shouldHaveSize(4)\n        callList[0].shouldBeInstanceOf<TtlCallable<*>>()\n        callList[1].shouldBeInstanceOf<TtlCallable<*>>()\n        callList[2].shouldBeNull()\n        callList[3].shouldBeInstanceOf<TtlCallable<*>>()\n    }\n\n    @Test\n    fun test_unwrap() {\n        assertNull(TtlCallable.unwrap<String>(null))\n\n        val callable = Callable { \"hello\" }\n        val ttlCallable = TtlCallable.get(callable)\n\n\n        assertSame(callable, TtlCallable.unwrap(callable))\n        assertSame(callable, TtlCallable.unwrap(ttlCallable))\n\n        assertSame(callable, TtlUnwrap.unwrap(callable))\n        assertSame(callable, TtlUnwrap.unwrap(ttlCallable))\n\n\n        assertEquals(listOf(callable), TtlCallable.unwraps(listOf(callable)))\n        assertEquals(listOf(callable), TtlCallable.unwraps(listOf(ttlCallable)))\n        assertEquals(listOf(callable, callable), TtlCallable.unwraps(listOf(ttlCallable, callable)))\n        assertEquals(listOf<Callable<String>>(), TtlCallable.unwraps<String>(null))\n    }\n\n    @AfterAll\n    fun afterAll() {\n        executorService.shutdown()\n        assertTrue(\"Fail to shutdown thread pool\", executorService.awaitTermination(1, TimeUnit.SECONDS))\n    }\n\n    companion object {\n        private val executorService = Executors.newFixedThreadPool(3).also { expandThreadPool(it) }\n    }\n}\n\n\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/TtlRunnableTest.kt",
    "content": "package com.alibaba.ttl\n\nimport com.alibaba.*\nimport com.alibaba.ttl.testmodel.DeepCopyFooTransmittableThreadLocal\nimport com.alibaba.ttl.testmodel.FooPojo\nimport com.alibaba.ttl.testmodel.FooTask\nimport com.alibaba.ttl.testmodel.Task\nimport io.kotest.assertions.throwables.shouldThrow\nimport io.kotest.assertions.timing.eventually\nimport io.kotest.core.spec.style.FunSpec\nimport io.kotest.matchers.collections.shouldHaveSize\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport io.kotest.matchers.string.shouldContain\nimport io.kotest.matchers.types.shouldBeInstanceOf\nimport org.junit.Assert.*\nimport java.util.concurrent.*\nimport java.util.concurrent.atomic.AtomicInteger\nimport kotlin.time.Duration.Companion.seconds\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass TtlRunnableTest : FunSpec({\n    lateinit var executorService: ExecutorService\n\n    beforeSpec {\n        executorService = Executors.newFixedThreadPool(3).also { expandThreadPool(it) }\n    }\n\n    afterSpec {\n        executorService.shutdown()\n        assertTrue(\"Fail to shutdown thread pool\", executorService.awaitTermination(1, TimeUnit.SECONDS))\n    }\n\n    test(\"runInCurrentThread\") {\n        val ttlInstances = createParentTtlInstances()\n\n        val task = Task(\"1\", ttlInstances)\n        val ttlRunnable = TtlRunnable.get(task)!!\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        // run in the *current* thread\n        ttlRunnable.run()\n\n\n        // child Inheritable\n        assertChildTtlValues(\"1\", task.copied)\n\n        // child do not affect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n\n    test(\"asyncRunByNewThread\") {\n        val ttlInstances = createParentTtlInstances()\n\n        val task = Task(\"1\", ttlInstances)\n        val thread1 = Thread(task)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        thread1.start()\n        thread1.join()\n\n\n        // child Inheritable\n        assertChildTtlValues(\"1\", task.copied)\n\n        // child do not affect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n\n    test(\"asyncRunByExecutorService\") {\n        val ttlInstances = createParentTtlInstances()\n\n        val task = Task(\"1\", ttlInstances)\n        val ttlRunnable = if (noTtlAgentRun()) TtlRunnable.get(task) else task\n\n        if (noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n        val submit = executorService.submit(ttlRunnable)\n        if (!noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n\n\n        submit.get()\n\n\n        // child Inheritable\n        assertChildTtlValues(\"1\", task.copied)\n\n        // child do not affect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n\n    test(\"remove_sameAsNotSet\") {\n        val ttlInstances = createParentTtlInstances()\n\n        // add and remove !!\n        newTtlInstanceAndPut(\"add and removed!\", ttlInstances).remove()\n\n\n        val task = Task(\"1\", ttlInstances)\n        val ttlRunnable = if (noTtlAgentRun()) TtlRunnable.get(task) else task\n\n        if (noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n        val submit = executorService.submit(ttlRunnable)\n        if (!noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n        submit.get()\n\n\n        // child Inheritable\n        assertChildTtlValues(\"1\", task.copied)\n\n        // child do not affect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n\n    test(\"callback_copy_beforeExecute_afterExecute\") {\n        val counterTtl = CounterTransmittableThreadLocal()\n        counterTtl.set(\"Foo\")\n\n        // do copy when decorate runnable\n        val ttlRunnable1 =\n            if (noTtlAgentRun()) TtlRunnable.get { /* do nothing Runnable */ } else Runnable { /* do nothing Runnable */ }\n        assertEquals(if (noTtlAgentRun()) 1 else 0, counterTtl.copyCounter.get())\n        assertEquals(0, counterTtl.beforeExecuteCounter.get())\n        assertEquals(0, counterTtl.afterExecuteCounter.get())\n\n        // do before/after when run\n        executorService.submit(ttlRunnable1).get()\n        assertEquals(1, counterTtl.copyCounter.get())\n        assertEquals(1, counterTtl.beforeExecuteCounter.get())\n        eventually(1.seconds) {\n            counterTtl.afterExecuteCounter.get() shouldBe 1\n        }\n        assertEquals(1, counterTtl.afterExecuteCounter.get())\n\n        // do before/after when run\n        executorService.submit(ttlRunnable1).get()\n        assertEquals(if (noTtlAgentRun()) 1 else 2, counterTtl.copyCounter.get())\n        assertEquals(2, counterTtl.beforeExecuteCounter.get())\n        eventually(1.seconds) {\n            counterTtl.afterExecuteCounter.get() shouldBe 2\n        }\n\n        // do copy when decorate runnable\n        val ttlRunnable2 =\n            if (noTtlAgentRun()) TtlRunnable.get { /* do nothing Runnable */ } else Runnable { /* do nothing Runnable */ }\n        assertEquals(if (noTtlAgentRun()) 2 else 2, counterTtl.copyCounter.get())\n        assertEquals(2, counterTtl.beforeExecuteCounter.get())\n        eventually(1.seconds) {\n            counterTtl.afterExecuteCounter.get() shouldBe 2\n        }\n\n        // do before/after when run\n        executorService.submit(ttlRunnable2).get()\n        assertEquals(if (noTtlAgentRun()) 2 else 3, counterTtl.copyCounter.get())\n        assertEquals(3, counterTtl.beforeExecuteCounter.get())\n        eventually(1.seconds) {\n            counterTtl.afterExecuteCounter.get() shouldBe 3\n        }\n    }\n\n    test(\"copyObject\") {\n        val ttlInstances = ConcurrentHashMap<String, TransmittableThreadLocal<FooPojo>>()\n\n        val parent = DeepCopyFooTransmittableThreadLocal()\n        parent.set(FooPojo(PARENT_CREATE_UNMODIFIED_IN_CHILD, 1))\n        ttlInstances[PARENT_CREATE_UNMODIFIED_IN_CHILD] = parent\n\n        val p = DeepCopyFooTransmittableThreadLocal()\n        p.set(FooPojo(PARENT_CREATE_MODIFIED_IN_CHILD, 2))\n        ttlInstances[PARENT_CREATE_MODIFIED_IN_CHILD] = p\n\n        val task = FooTask(\"1\", ttlInstances)\n        val ttlRunnable = if (noTtlAgentRun()) TtlRunnable.get(task) else task\n\n        if (noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            val after = DeepCopyFooTransmittableThreadLocal()\n            after.set(FooPojo(PARENT_CREATE_AFTER_CREATE_CHILD, 4))\n            ttlInstances[PARENT_CREATE_AFTER_CREATE_CHILD] = after\n        }\n        val submit = executorService.submit(ttlRunnable)\n        if (!noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            val after = DeepCopyFooTransmittableThreadLocal()\n            after.set(FooPojo(PARENT_CREATE_AFTER_CREATE_CHILD, 4))\n            ttlInstances[PARENT_CREATE_AFTER_CREATE_CHILD] = after\n        }\n\n        submit.get()\n\n        // child Inheritable\n        assertEquals(3, task.copied.size.toLong())\n        assertEquals(FooPojo(PARENT_CREATE_UNMODIFIED_IN_CHILD, 1), task.copied[PARENT_CREATE_UNMODIFIED_IN_CHILD])\n        assertEquals(FooPojo(PARENT_CREATE_MODIFIED_IN_CHILD + \"1\", 2), task.copied[PARENT_CREATE_MODIFIED_IN_CHILD])\n        assertEquals(FooPojo(CHILD_CREATE + 1, 3), task.copied[CHILD_CREATE + 1])\n\n        // child do not affect parent\n        val copied = copyTtlValues(ttlInstances)\n        assertEquals(3, copied.size.toLong())\n        assertEquals(FooPojo(PARENT_CREATE_UNMODIFIED_IN_CHILD, 1), copied[PARENT_CREATE_UNMODIFIED_IN_CHILD])\n        assertEquals(FooPojo(PARENT_CREATE_MODIFIED_IN_CHILD, 2), copied[PARENT_CREATE_MODIFIED_IN_CHILD])\n        assertEquals(FooPojo(PARENT_CREATE_AFTER_CREATE_CHILD, 4), copied[PARENT_CREATE_AFTER_CREATE_CHILD])\n    }\n\n    test(\"releaseTtlValueReferenceAfterRun\") {\n        val ttlInstances = createParentTtlInstances()\n\n        val task = Task(\"1\", ttlInstances)\n        val ttlRunnable = TtlRunnable.get(task, true)\n\n        assertNull(executorService.submit(ttlRunnable).get())\n\n        val exception = shouldThrow<ExecutionException> {\n            executorService.submit(ttlRunnable).get()\n        }\n        exception.cause.shouldBeInstanceOf<IllegalStateException>()\n        exception.message shouldContain \"TTL value reference is released after run!\"\n    }\n\n    test(\"get_same\") {\n        val task = Task(\"1\")\n        val ttlRunnable = TtlRunnable.get(task)!!\n        assertSame(task, ttlRunnable.runnable)\n    }\n\n    test(\"get_idempotent\") {\n        val task = TtlRunnable.get(Task(\"1\"))\n\n        shouldThrow<IllegalStateException> {\n            TtlRunnable.get(task)\n        }.message shouldContain \"Already TtlRunnable\"\n    }\n\n    test(\"et_nullInput\") {\n        assertNull(TtlRunnable.get(null))\n    }\n\n    test(\"gets\") {\n        val task1 = Task(\"1\")\n        val task2 = Task(\"2\")\n        val task3 = Task(\"3\")\n\n        val taskList = TtlRunnable.gets(listOf<Runnable?>(task1, task2, null, task3))\n\n        taskList.shouldHaveSize(4)\n\n        taskList[0].shouldBeInstanceOf<TtlRunnable>()\n        taskList[1].shouldBeInstanceOf<TtlRunnable>()\n        taskList[2].shouldBeNull()\n        taskList[3].shouldBeInstanceOf<TtlRunnable>()\n    }\n\n    test(\"unwrap\") {\n        assertNull(TtlRunnable.unwrap(null))\n\n        val runnable = Runnable {}\n        val ttlRunnable = TtlRunnable.get(runnable)\n\n\n        assertSame(runnable, TtlRunnable.unwrap(runnable))\n        assertSame(runnable, TtlRunnable.unwrap(ttlRunnable))\n\n        assertSame(runnable, TtlUnwrap.unwrap(runnable))\n        assertSame(runnable, TtlUnwrap.unwrap(ttlRunnable))\n\n\n        assertEquals(listOf(runnable), TtlRunnable.unwraps(listOf(runnable)))\n        assertEquals(listOf(runnable), TtlRunnable.unwraps(listOf(ttlRunnable)))\n        assertEquals(listOf(runnable, runnable), TtlRunnable.unwraps(listOf(ttlRunnable, runnable)))\n        assertEquals(listOf<Runnable>(), TtlRunnable.unwraps(null))\n    }\n})\n\nprivate class CounterTransmittableThreadLocal : TransmittableThreadLocal<String?>() {\n    val copyCounter = AtomicInteger()\n    val beforeExecuteCounter = AtomicInteger()\n    val afterExecuteCounter = AtomicInteger()\n\n    override fun copy(parentValue: String?): String? {\n        copyCounter.incrementAndGet()\n        return super.copy(parentValue)\n    }\n\n    override fun beforeExecute() {\n        beforeExecuteCounter.incrementAndGet()\n        super.beforeExecute()\n    }\n\n    override fun afterExecute() {\n        afterExecuteCounter.incrementAndGet()\n        super.afterExecute()\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/TtlTimerTaskTest.kt",
    "content": "package com.alibaba.ttl\n\nimport io.kotest.core.spec.style.AnnotationSpec\nimport org.junit.Assert.*\nimport java.util.*\n\n@Suppress(\"DEPRECATION\")\nclass TtlTimerTaskTest : AnnotationSpec() {\n    @Test\n    fun test_get() {\n        assertNull(TtlTimerTask.get(null))\n\n        val timerTask = object : TimerTask() {\n            override fun run() {}\n        }\n\n        val ttlTimerTask = TtlTimerTask.get(timerTask)\n        assertTrue(ttlTimerTask is TtlTimerTask)\n    }\n\n    @Test\n    fun test_unwrap() {\n        assertNull(TtlTimerTask.unwrap(null))\n\n        val timerTask = object : TimerTask() {\n            override fun run() {}\n        }\n        val ttlTimerTask = TtlTimerTask.get(timerTask)\n\n\n        assertSame(timerTask, TtlTimerTask.unwrap(timerTask))\n        assertSame(timerTask, TtlTimerTask.unwrap(ttlTimerTask))\n\n\n        assertEquals(listOf(timerTask), TtlTimerTask.unwraps(listOf(timerTask)))\n        assertEquals(listOf(timerTask), TtlTimerTask.unwraps(listOf(ttlTimerTask)))\n        assertEquals(listOf(timerTask, timerTask), TtlTimerTask.unwraps(listOf(ttlTimerTask, timerTask)))\n        assertEquals(listOf<TimerTask>(), TtlTimerTask.unwraps(null))\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/TtlWrappersTest.kt",
    "content": "package com.alibaba.ttl\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.ttl.TtlUnwrap.unwrap\nimport com.alibaba.ttl.TtlWrappers.*\nimport io.kotest.core.spec.style.AnnotationSpec\nimport org.junit.Assert.*\nimport java.util.concurrent.Executors\nimport java.util.concurrent.TimeUnit\nimport java.util.function.*\nimport java.util.function.Function\n\nclass TtlWrappersTest : AnnotationSpec() {\n\n    @Test\n    fun test_null() {\n        val supplier: Supplier<String>? = null\n        @Suppress(\"DEPRECATION\")\n        assertNull(wrap(supplier))\n        assertNull(wrapSupplier(supplier))\n        assertNull(unwrap(supplier))\n\n        val consumer: Consumer<String>? = null\n        @Suppress(\"DEPRECATION\")\n        assertNull(wrap(consumer))\n        assertNull(wrapConsumer(consumer))\n        assertNull(unwrap(consumer))\n\n        val biConsumer: BiConsumer<String, String>? = null\n        @Suppress(\"DEPRECATION\")\n        assertNull(wrap(biConsumer))\n        assertNull(wrapBiConsumer(biConsumer))\n        assertNull(unwrap(biConsumer))\n\n        val function: Function<String, String>? = null\n        @Suppress(\"DEPRECATION\")\n        assertNull(wrap(function))\n        assertNull(wrapFunction(function))\n        assertNull(unwrap(function))\n\n        val biFunction: BiFunction<String, String, String>? = null\n        @Suppress(\"DEPRECATION\")\n        assertNull(wrap(biFunction))\n        assertNull(wrapBiFunction(biFunction))\n        assertNull(unwrap(biFunction))\n    }\n\n    @Test\n    fun wrap_ReWrap_Unwrap_same() {\n        // Supplier\n        val supplier = Supplier { 42 }\n\n        @Suppress(\"DEPRECATION\")\n        val ttlSupplier = wrap(supplier)\n        @Suppress(\"DEPRECATION\")\n        assertSame(ttlSupplier, wrap(ttlSupplier))\n        assertSame(ttlSupplier, wrapSupplier(ttlSupplier))\n        assertSame(supplier, unwrap(ttlSupplier))\n\n        val ttlSupplier2 = wrapSupplier(supplier)\n        assertSame(ttlSupplier2, wrapSupplier(ttlSupplier2))\n        @Suppress(\"DEPRECATION\")\n        assertSame(ttlSupplier2, wrap(ttlSupplier2))\n        assertSame(supplier, unwrap(ttlSupplier2))\n\n        // Consumer\n        val consumer = Consumer<String> {}\n\n        @Suppress(\"DEPRECATION\")\n        val ttlConsumer = wrap(consumer)\n        @Suppress(\"DEPRECATION\")\n        assertSame(ttlConsumer, wrap(ttlConsumer))\n        assertSame(ttlConsumer, wrapConsumer(ttlConsumer))\n        assertSame(consumer, unwrap(ttlConsumer))\n\n        val ttlConsumer2 = wrapConsumer(consumer)\n        assertSame(ttlConsumer2, wrapConsumer(ttlConsumer2))\n        @Suppress(\"DEPRECATION\")\n        assertSame(ttlConsumer2, wrap(ttlConsumer2))\n        assertSame(consumer, unwrap(ttlConsumer2))\n\n        // BiConsumer\n        val biConsumer = BiConsumer<String, String> { _, _ -> }\n\n        @Suppress(\"DEPRECATION\")\n        val ttlBiConsumer = wrap(biConsumer)\n        @Suppress(\"DEPRECATION\")\n        assertSame(ttlBiConsumer, wrap(ttlBiConsumer))\n        assertSame(ttlBiConsumer, wrapBiConsumer(ttlBiConsumer))\n        assertSame(biConsumer, unwrap(ttlBiConsumer))\n\n        val ttlBiConsumer2 = wrapBiConsumer(biConsumer)\n        assertSame(ttlBiConsumer2, wrapBiConsumer(ttlBiConsumer2))\n        @Suppress(\"DEPRECATION\")\n        assertSame(ttlBiConsumer2, wrap(ttlBiConsumer2))\n        assertSame(biConsumer, unwrap(ttlBiConsumer2))\n\n        // Function\n        val function = Function<String, String> { \"\" }\n\n        @Suppress(\"DEPRECATION\")\n        val ttlFunction = wrap(function)\n        @Suppress(\"DEPRECATION\")\n        assertSame(ttlFunction, wrap(ttlFunction))\n        assertSame(ttlFunction, wrapFunction(ttlFunction))\n        assertSame(function, unwrap(ttlFunction))\n\n        val ttlFunction2 = wrapFunction(function)\n        assertSame(ttlFunction2, wrapFunction(ttlFunction2))\n        @Suppress(\"DEPRECATION\")\n        assertSame(ttlFunction2, wrap(ttlFunction2))\n        assertSame(function, unwrap(ttlFunction2))\n\n        // BiFunction\n        val biFunction = BiFunction<String, String, String> { _, _ -> \"\" }\n\n        @Suppress(\"DEPRECATION\")\n        val ttlBiFunction = wrap(biFunction)\n        @Suppress(\"DEPRECATION\")\n        assertSame(ttlBiFunction, wrap(ttlBiFunction))\n        assertSame(ttlBiFunction, wrapBiFunction(ttlBiFunction))\n        assertSame(biFunction, unwrap(ttlBiFunction))\n\n        val ttlBiFunction2 = wrapBiFunction(biFunction)\n        assertSame(ttlBiFunction2, wrapBiFunction(ttlBiFunction2))\n        @Suppress(\"DEPRECATION\")\n        assertSame(ttlBiFunction2, wrap(ttlBiFunction2))\n        assertSame(biFunction, unwrap(ttlBiFunction2))\n    }\n\n    @Test\n    fun test_Supplier() {\n        val ttl = TransmittableThreadLocal<String>()\n\n        fun Supplier<String>.ttlWrapThenAsRunnable(): Runnable {\n            @Suppress(\"DEPRECATION\")\n            val wrap = wrap(this)!!\n            return Runnable { wrap.get() }\n        }\n\n        ttl.set(\"1\")\n        Supplier<String> {\n            assertEquals(\"1\", ttl.get())\n            \"world\"\n        }.ttlWrapThenAsRunnable().let {\n            ttl.set(\"main\")\n\n            executorService.submit(it).get()\n            assertEquals(\"main\", ttl.get())\n        }\n\n        ttl.set(\"2\")\n        Supplier<String> {\n            assertEquals(\"2\", ttl.get())\n            \"world\"\n        }.ttlWrapThenAsRunnable().let {\n            ttl.set(\"main\")\n\n            executorService.submit(it).get()\n            assertEquals(\"main\", ttl.get())\n        }\n    }\n\n    @Test\n    fun test_Consumer() {\n        fun Consumer<String>.ttlWrapThenAsRunnable(): Runnable {\n            @Suppress(\"DEPRECATION\")\n            val wrap = wrap(this)!!\n            return Runnable { wrap.accept(\"hello ${System.nanoTime()}\") }\n        }\n\n        val ttl = TransmittableThreadLocal<String>()\n\n        ttl.set(\"1\")\n        Consumer<String> {\n            assertEquals(\"1\", ttl.get())\n        }.ttlWrapThenAsRunnable().let {\n            ttl.set(\"main\")\n\n            executorService.submit(it).get()\n            assertEquals(\"main\", ttl.get())\n        }\n\n        ttl.set(\"2\")\n        Consumer<String> {\n            assertEquals(\"2\", ttl.get())\n        }.ttlWrapThenAsRunnable().let {\n            ttl.set(\"main\")\n\n            executorService.submit(it).get()\n            assertEquals(\"main\", ttl.get())\n        }\n    }\n\n    @Test\n    fun test_BiConsumer() {\n        fun BiConsumer<String, String>.ttlWrapThenAsRunnable(): Runnable {\n            @Suppress(\"DEPRECATION\")\n            val wrap = wrap(this)!!\n            return Runnable { wrap.accept(\"hello ${System.nanoTime()}\", \"world ${System.nanoTime()}\") }\n        }\n\n        val ttl = TransmittableThreadLocal<String>()\n\n        ttl.set(\"1\")\n        BiConsumer<String, String> { _, _ ->\n            assertEquals(\"1\", ttl.get())\n        }.ttlWrapThenAsRunnable().let {\n            ttl.set(\"main\")\n\n            executorService.submit(it).get()\n            assertEquals(\"main\", ttl.get())\n        }\n\n        ttl.set(\"2\")\n        BiConsumer<String, String> { _, _ ->\n            assertEquals(\"2\", ttl.get())\n        }.ttlWrapThenAsRunnable().let {\n            ttl.set(\"main\")\n\n            executorService.submit(it).get()\n            assertEquals(\"main\", ttl.get())\n        }\n    }\n\n    @Test\n    fun test_Function() {\n        fun Function<String, String>.ttlWrapThenAsRunnable(): Runnable {\n            @Suppress(\"DEPRECATION\")\n            val wrap = wrap(this)!!\n            return Runnable { wrap.apply(\"hello ${System.nanoTime()}\") }\n        }\n\n        val ttl = TransmittableThreadLocal<String>()\n\n        ttl.set(\"1\")\n        Function<String, String> {\n            assertEquals(\"1\", ttl.get())\n            \"world\"\n        }.ttlWrapThenAsRunnable().let {\n            ttl.set(\"main\")\n\n            executorService.submit(it).get()\n            assertEquals(\"main\", ttl.get())\n        }\n\n        ttl.set(\"2\")\n        Function<String, String> {\n            assertEquals(\"2\", ttl.get())\n            \"world\"\n        }.ttlWrapThenAsRunnable().let {\n            ttl.set(\"main\")\n\n            executorService.submit(it).get()\n            assertEquals(\"main\", ttl.get())\n        }\n    }\n\n    @Test\n    fun test_BiFunction() {\n        fun BiFunction<String, String, String>.ttlWrapThenAsRunnable(): Runnable {\n            @Suppress(\"DEPRECATION\")\n            val wrap = wrap(this)!!\n            return Runnable { wrap.apply(\"hello ${System.nanoTime()}\", \"world\") }\n        }\n\n        val ttl = TransmittableThreadLocal<String>()\n\n        ttl.set(\"1\")\n        BiFunction<String, String, String> { _, _ ->\n            assertEquals(\"1\", ttl.get())\n            \"world\"\n        }.ttlWrapThenAsRunnable().let {\n            ttl.set(\"main\")\n\n            executorService.submit(it).get()\n            assertEquals(\"main\", ttl.get())\n        }\n\n        ttl.set(\"2\")\n        BiFunction<String, String, String> { _, _ ->\n            assertEquals(\"2\", ttl.get())\n            \"world\"\n        }.ttlWrapThenAsRunnable().let {\n            ttl.set(\"main\")\n\n            executorService.submit(it).get()\n            assertEquals(\"main\", ttl.get())\n        }\n    }\n\n    @AfterAll\n    fun afterAll() {\n        executorService.shutdown()\n        assertTrue(\"Fail to shutdown thread pool\", executorService.awaitTermination(1, TimeUnit.SECONDS))\n    }\n\n    companion object {\n        private val executorService = Executors.newFixedThreadPool(3).also { expandThreadPool(it) }\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/forkjoin/ForkJoinPool4RunnableCallableTest.kt",
    "content": "package com.alibaba.ttl.forkjoin\n\nimport com.alibaba.*\nimport com.alibaba.ttl.TtlCallable\nimport com.alibaba.ttl.TtlRunnable\nimport com.alibaba.ttl.testmodel.Call\nimport com.alibaba.ttl.testmodel.Task\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.shouldBe\nimport java.util.concurrent.ForkJoinPool\n\nprivate val pool = ForkJoinPool()\n\nclass ForkJoinPool4RunnableCallableTest : AnnotationSpec() {\n\n    @Test\n    fun test_Runnable() {\n        val ttlInstances = createParentTtlInstances()\n\n        val task = Task(\"1\", ttlInstances)\n        val ttlRunnable = if (noTtlAgentRun()) TtlRunnable.get(task) else task\n\n        if (noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n        val submit = pool.submit(ttlRunnable)\n        if (!noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n\n\n        submit.get()\n\n\n        // child Inheritable\n        assertChildTtlValues(\"1\", task.copied)\n\n        // child do not effect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n\n    @Test\n    fun test_Callable() {\n        val ttlInstances = createParentTtlInstances()\n\n        val call = Call(\"1\", ttlInstances)\n        val ttlCallable = if (noTtlAgentRun()) TtlCallable.get(call) else call\n\n        if (noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n        val future = pool.submit(ttlCallable)\n        if (!noTtlAgentRun()) {\n            // create after new Task, won't see parent value in in task!\n            createParentTtlInstancesAfterCreateChild(ttlInstances)\n        }\n\n        future.get() shouldBe \"ok\"\n\n\n        // child Inheritable\n        assertChildTtlValues(\"1\", call.copied)\n\n        // child do not effect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/forkjoin/ForkJoinPool4StreamTest.kt",
    "content": "package com.alibaba.ttl.forkjoin\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.threadpool.agent.TtlAgent\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport java.util.concurrent.ForkJoinPool\n\n\nprivate const val hello = \"hello\"\n\nclass ForkJoinPool4StreamTest : AnnotationSpec() {\n\n    @Test\n    fun test_stream_with_agent() {\n        if (!TtlAgent.isTtlAgentLoaded()) return\n\n        expandThreadPool(ForkJoinPool.commonPool())\n\n        val ttl = TransmittableThreadLocal<String?>()\n        ttl.set(hello)\n\n        (0..100).map {\n            ForkJoinPool.commonPool().submit {\n                ttl.get() shouldBe hello\n            }\n        }.forEach { it.get() }\n\n        (0..1000).toList().stream().parallel().mapToInt {\n            ttl.get() shouldBe hello\n\n            it\n        }.sum() shouldBe (0..1000).sum()\n    }\n\n    @Test\n    fun test_stream_no_agent() {\n        if (TtlAgent.isTtlAgentLoaded()) return\n\n        val name = Thread.currentThread().name\n        expandThreadPool(ForkJoinPool.commonPool())\n\n        val ttl = TransmittableThreadLocal<String?>()\n        ttl.set(hello)\n\n        (0..100).map {\n            ForkJoinPool.commonPool().submit {\n                if (Thread.currentThread().name == name) ttl.get() shouldBe hello\n                else ttl.get().shouldBeNull()\n            }\n        }.forEach { it.get() }\n\n        (0..1000).toList().stream().parallel().mapToInt {\n            if (Thread.currentThread().name == name) ttl.get() shouldBe hello\n            else ttl.get().shouldBeNull()\n\n            it\n        }.sum() shouldBe (0..1000).sum()\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/forkjoin/recursive_action/TtlRecursiveActionTest.kt",
    "content": "package com.alibaba.ttl.forkjoin.recursive_action\n\nimport com.alibaba.*\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.TtlRecursiveAction\nimport io.kotest.core.spec.style.AnnotationSpec\nimport mu.KotlinLogging\nimport java.util.concurrent.ConcurrentMap\nimport java.util.concurrent.ForkJoinPool\n\n\nprivate val pool = ForkJoinPool()\nprivate val singleThreadPool = ForkJoinPool(1)\n\n/**\n * TtlRecursiveAction test class\n *\n * @author LNAmp\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass TtlRecursiveActionTest : AnnotationSpec() {\n    @Test\n    fun test_TtlRecursiveTask_asyncWithForkJoinPool() {\n        run_test_with_pool(pool)\n    }\n\n    @Test\n    fun test_TtlRecursiveTask_asyncWithSingleThreadForkJoinPool_changeValue() {\n        run_test_with_pool(singleThreadPool)\n    }\n}\n\nprivate fun run_test_with_pool(forkJoinPool: ForkJoinPool) {\n    val ttlInstances = createParentTtlInstances()\n\n    val printAction = PrintAction(1..42, ttlInstances)\n\n    // create after new Task, won't see parent value in in task!\n    createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n    val future = forkJoinPool.submit(printAction)\n    future.get()\n\n\n    // child Inheritable\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD /* Not change*/\n        ),\n        printAction.copied\n    )\n\n    // left grand Task Inheritable, changed value\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD + PrintAction.CHANGE_POSTFIX /* CHANGED */\n        ),\n        printAction.leftSubAction.copied\n    )\n\n    // right grand Task Inheritable, not change value\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD /* Not change*/\n        ),\n        printAction.rightSubAction.copied\n    )\n\n    // child do not affect parent\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD,\n            PARENT_CREATE_AFTER_CREATE_CHILD to PARENT_CREATE_AFTER_CREATE_CHILD\n        ),\n        copyTtlValues(ttlInstances)\n    )\n}\n\n\n/**\n * A test demo class\n *\n * @author LNAmp\n */\nprivate class PrintAction(\n    private val numbers: IntRange,\n    private val ttlMap: ConcurrentMap<String, TransmittableThreadLocal<String>>,\n    private val changeTtlValue: Boolean = false\n) : TtlRecursiveAction() {\n    private val logger = KotlinLogging.logger {}\n\n\n    lateinit var copied: Map<String, Any>\n    lateinit var leftSubAction: PrintAction\n    lateinit var rightSubAction: PrintAction\n\n    override fun compute() {\n        if (changeTtlValue) {\n            modifyParentTtlInstances(CHANGE_POSTFIX, ttlMap)\n        }\n\n        try {\n            if (numbers.count() <= 10) {\n                logger.info { \"print numbers: $numbers\" }\n            } else {\n                val mid = numbers.first + numbers.count() / 2\n\n                // left -> change! right -> not change.\n                val left = PrintAction(numbers.first until mid, ttlMap, true)\n                val right = PrintAction(mid..numbers.last, ttlMap, false)\n                leftSubAction = left\n                rightSubAction = right\n\n                left.fork()\n                right.fork()\n                left.join()\n                right.join()\n            }\n        } finally {\n            this.copied = copyTtlValues(this.ttlMap)\n        }\n    }\n\n    companion object {\n        const val CHANGE_POSTFIX = \" + 1\"\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/forkjoin/recursive_task/TtlRecursiveTaskTest.kt",
    "content": "package com.alibaba.ttl.forkjoin.recursive_task\n\nimport com.alibaba.*\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.TtlRecursiveTask\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.shouldBe\nimport java.util.concurrent.*\n\nprivate val pool = ForkJoinPool()\nprivate val singleThreadPool = ForkJoinPool(1)\n\n/**\n * @author LNAmp\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass TtlRecursiveTaskTest : AnnotationSpec() {\n    @Test\n    fun test_TtlRecursiveTask_asyncWith_ForkJoinPool() {\n        run_test_with_pool(pool)\n    }\n\n    @Test\n    fun test_TtlRecursiveTask_asyncWith_SingleThreadForkJoinPool() {\n        run_test_with_pool(singleThreadPool)\n    }\n}\n\nprivate fun run_test_with_pool(forkJoinPool: ForkJoinPool) {\n    val ttlInstances = createParentTtlInstances()\n\n    val numbers = 0..42\n    val sumTask: ForkJoinTask<Int> =\n        if (noTtlAgentRun()) TtlSumTask(numbers, ttlInstances) else SumTask(numbers, ttlInstances)\n\n    // create after new Task, won't see parent value in in task!\n    createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n    val future = forkJoinPool.submit(sumTask)\n    future.get() shouldBe numbers.sum()\n\n    // child Inheritable\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD /* Not change*/\n        ),\n        (sumTask as Getter).getcopied()\n    )\n\n    // left grand Task Inheritable, changed value\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD + CHANGE_POSTFIX /* CHANGED */\n        ),\n        sumTask.getLeftSubTask().getcopied()\n    )\n\n    // right grand Task Inheritable, not change value\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD /* Not change*/\n        ),\n        sumTask.getRightSubTask().getcopied()\n    )\n\n    // child do not affect parent\n    assertTtlValues(\n        mapOf(\n            PARENT_CREATE_UNMODIFIED_IN_CHILD to PARENT_CREATE_UNMODIFIED_IN_CHILD,\n            PARENT_CREATE_MODIFIED_IN_CHILD to PARENT_CREATE_MODIFIED_IN_CHILD,\n            PARENT_CREATE_AFTER_CREATE_CHILD to PARENT_CREATE_AFTER_CREATE_CHILD\n        ),\n        copyTtlValues(ttlInstances)\n    )\n}\n\n\nprivate interface Getter {\n    fun getcopied(): Map<String, Any>\n    fun getLeftSubTask(): Getter\n    fun getRightSubTask(): Getter\n}\n\n/**\n * A test demo class\n *\n * @author LNAmp\n * @see com.alibaba.ttl.TtlRecursiveTask\n */\nprivate open class TtlSumTask(\n    private val numbers: IntRange,\n    private val ttlMap: ConcurrentMap<String, TransmittableThreadLocal<String>>,\n    private val changeTtlValue: Boolean = false\n) : TtlRecursiveTask<Int>(), Getter {\n\n    lateinit var copied: Map<String, Any>\n    lateinit var leftSubTask: TtlSumTask\n    lateinit var rightSubTask: TtlSumTask\n\n    override fun compute(): Int {\n        if (changeTtlValue) {\n            modifyParentTtlInstances(CHANGE_POSTFIX, ttlMap)\n        }\n\n        try {\n            return if (numbers.count() <= 10) {\n                numbers.sum()\n            } else {\n                val mid = numbers.first + numbers.count() / 2\n\n                // left -> change! right -> not change.\n                val left = TtlSumTask(numbers.first until mid, ttlMap, true)\n                val right = TtlSumTask(mid..numbers.last, ttlMap, false)\n                this.leftSubTask = left\n                this.rightSubTask = right\n\n                left.fork()\n                right.fork()\n                left.join() + right.join()\n            }\n        } finally {\n            this.copied = copyTtlValues(this.ttlMap)\n        }\n    }\n\n    override fun getcopied(): Map<String, Any> = copied\n\n    override fun getLeftSubTask(): Getter = leftSubTask\n\n    override fun getRightSubTask(): Getter = rightSubTask\n}\n\n\n/**\n * A test demo class\n */\nprivate class SumTask(\n    private val numbers: IntRange,\n    private val ttlMap: ConcurrentMap<String, TransmittableThreadLocal<String>>,\n    private val changeTtlValue: Boolean = false\n) : RecursiveTask<Int>(), Getter {\n\n    lateinit var copied: Map<String, Any>\n    lateinit var leftSubTask: SumTask\n    lateinit var rightSubTask: SumTask\n\n    override fun compute(): Int {\n        if (changeTtlValue) {\n            modifyParentTtlInstances(CHANGE_POSTFIX, ttlMap)\n        }\n\n        try {\n            return if (numbers.count() <= 10) {\n                numbers.sum()\n            } else {\n                val mid = numbers.first + numbers.count() / 2\n\n                // left -> change! right -> not change.\n                val left = SumTask(this.numbers.first until mid, ttlMap, true)\n                val right = SumTask(mid..numbers.last, ttlMap, false)\n                this.leftSubTask = left\n                this.rightSubTask = right\n\n                left.fork()\n                right.fork()\n                left.join() + right.join()\n            }\n        } finally {\n            this.copied = copyTtlValues(this.ttlMap)\n        }\n    }\n\n    override fun getcopied(): Map<String, Any> = copied\n\n    override fun getLeftSubTask(): Getter = leftSubTask\n\n    override fun getRightSubTask(): Getter = rightSubTask\n}\n\nconst val CHANGE_POSTFIX = \" + 1\"\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/reported_bugs/Bug70_Test.kt",
    "content": "package com.alibaba.ttl.reported_bugs\n\nimport com.alibaba.noTtlAgentRun\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.TtlRunnable\nimport org.junit.Assert.assertEquals\nimport org.junit.Test\nimport java.util.concurrent.Executors\nimport java.util.concurrent.FutureTask\nimport java.util.concurrent.atomic.AtomicReference\nimport kotlin.concurrent.thread\n\n/**\n * Bug URL: https://github.com/alibaba/transmittable-thread-local/issues/70\n * Reporter: @aftersss\n */\nclass Bug70_Test {\n\n    @Test\n    fun test_bug70() {\n        val hello = \"hello\"\n        val executorService = Executors.newSingleThreadExecutor()\n        val threadLocal = TransmittableThreadLocal<String>().apply { set(hello) }\n        assertEquals(hello, threadLocal.get())\n\n        FutureTask { threadLocal.get() }.also {\n            val runnable = if (noTtlAgentRun()) TtlRunnable.get(it) else it\n            executorService.submit(runnable)\n            assertEquals(hello, it.get())\n        }\n\n        val taskRef = AtomicReference<FutureTask<String>>()\n        thread(name = \"the thread for run executor action\") {\n            FutureTask { threadLocal.get() }.also {\n                val runnable = if (noTtlAgentRun()) TtlRunnable.get(it, false, false) else it\n                executorService.submit(runnable)\n                taskRef.set(it)\n            }\n        }.join()\n        assertEquals(hello, taskRef.get().get())\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/testmodel/Call.kt",
    "content": "package com.alibaba.ttl.testmodel\n\nimport com.alibaba.createChildTtlInstancesAndModifyParentTtlInstances\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport java.util.concurrent.Callable\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.ConcurrentMap\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass Call(private val tag: String, private val ttlInstances: ConcurrentMap<String, TransmittableThreadLocal<String>> = ConcurrentHashMap()) : Callable<String> {\n\n    lateinit var copied: Map<String, String>\n\n    val isCopied: Boolean\n        get() = ::copied.isInitialized\n\n    override fun call(): String {\n        copied = createChildTtlInstancesAndModifyParentTtlInstances(tag, ttlInstances)\n        return \"ok\"\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/testmodel/DeepCopyFooTransmittableThreadLocal.kt",
    "content": "package com.alibaba.ttl.testmodel\n\nimport com.alibaba.ttl.TransmittableThreadLocal\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass DeepCopyFooTransmittableThreadLocal : TransmittableThreadLocal<FooPojo>() {\n    override fun copy(parentValue: FooPojo?): FooPojo? = parentValue?.copy()\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/testmodel/FooPojo.kt",
    "content": "package com.alibaba.ttl.testmodel\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\ndata class FooPojo(var name: String?, var age: Int)\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/testmodel/FooTask.kt",
    "content": "package com.alibaba.ttl.testmodel\n\nimport com.alibaba.CHILD_CREATE\nimport com.alibaba.PARENT_CREATE_MODIFIED_IN_CHILD\nimport com.alibaba.copyTtlValues\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport mu.KotlinLogging\nimport java.util.concurrent.ConcurrentMap\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass FooTask(\n    private val value: String,\n    private val ttlInstances: ConcurrentMap<String, TransmittableThreadLocal<FooPojo>>\n) : Runnable {\n    private val logger = KotlinLogging.logger {}\n\n    @Volatile\n    lateinit var copied: Map<String, FooPojo>\n\n    override fun run() {\n        try {\n            // Add new\n            val child = DeepCopyFooTransmittableThreadLocal()\n            child.set(FooPojo(CHILD_CREATE + value, 3))\n            ttlInstances[CHILD_CREATE + value] = child\n\n            // modify the parent key\n            ttlInstances[PARENT_CREATE_MODIFIED_IN_CHILD]!!.get()!!.name =\n                ttlInstances[PARENT_CREATE_MODIFIED_IN_CHILD]!!.get()!!.name + value\n\n            copied = copyTtlValues(ttlInstances)\n\n            logger.info { \"Task $value finished!\" }\n        } catch (e: Throwable) {\n            e.printStackTrace()\n        }\n\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/testmodel/Task.kt",
    "content": "package com.alibaba.ttl.testmodel\n\nimport com.alibaba.createChildTtlInstancesAndModifyParentTtlInstances\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport java.util.concurrent.ArrayBlockingQueue\nimport java.util.concurrent.ConcurrentHashMap\nimport java.util.concurrent.ConcurrentMap\nimport java.util.concurrent.TimeUnit\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass Task(\n    private val tag: String,\n    private val ttlInstances: ConcurrentMap<String, TransmittableThreadLocal<String>> = ConcurrentHashMap()\n) : Runnable {\n\n    private val queue = ArrayBlockingQueue<Map<String, String>>(1)\n\n    val copied: Map<String, String>\n        get() = queue.poll(1, TimeUnit.SECONDS)!!\n\n    override fun run() {\n        val map = createChildTtlInstancesAndModifyParentTtlInstances(tag, ttlInstances)\n        queue.put(map)\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/threadlocal_integration/ThreadLocalIntegrationTest.kt",
    "content": "package com.alibaba.ttl.threadlocal_integration\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.ttl.TransmittableThreadLocal.Transmitter.*\nimport com.alibaba.ttl.TtlCopier\nimport com.alibaba.ttl.threadpool.TtlExecutors\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.booleans.shouldBeFalse\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.shouldBe\nimport java.util.*\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport java.util.concurrent.LinkedBlockingQueue\nimport java.util.concurrent.TimeUnit\nimport kotlin.concurrent.thread\n\nclass ThreadLocalIntegrationTest : AnnotationSpec() {\n    @Test\n    fun threadLocal_do_NOT_transmit() {\n        val threadLocal = ThreadLocal<String>()\n        unregisterThreadLocal(threadLocal).shouldBeFalse()\n        threadLocal.set(PARENT)\n\n        assertNotTransmit(threadLocal)\n    }\n\n    private fun assertNotTransmit(threadLocal: ThreadLocal<String>) {\n        val future = executorService.submit {\n            threadLocal.get().shouldBeNull()\n            threadLocal.set(CHILD)\n        }\n\n        threadLocal.get() shouldBe PARENT\n        future.get(1, TimeUnit.SECONDS)\n\n        unregisterThreadLocal(threadLocal).shouldBeFalse()\n    }\n\n    @Test\n    fun threadLocal_registerThreadLocalWithShadowCopier_do_transmit() {\n        val threadLocal = ThreadLocal<String>()\n        unregisterThreadLocal(threadLocal).shouldBeFalse()\n        threadLocal.set(PARENT)\n\n        registerThreadLocalWithShadowCopier(threadLocal).shouldBeTrue()\n        assertTransmitShadowCopy(threadLocal)\n\n        // Unregister\n        unregisterThreadLocal(threadLocal).shouldBeTrue()\n        assertNotTransmit(threadLocal)\n    }\n\n\n    private fun assertTransmitShadowCopy(threadLocal: ThreadLocal<String>) {\n        val future = executorService.submit {\n            threadLocal.get() shouldBe PARENT\n            threadLocal.set(CHILD)\n        }\n\n        threadLocal.get() shouldBe PARENT\n        future.get(1, TimeUnit.SECONDS)\n    }\n\n    @Test\n    fun threadLocal_registerThreadLocal_and_force() {\n        val threadLocal = ThreadLocal<String>()\n        unregisterThreadLocal(threadLocal).shouldBeFalse()\n        registerThreadLocal(threadLocal, APPEND_SUFFIX_COPIER).shouldBeTrue()\n\n        threadLocal.set(PARENT)\n        assertTransmitSuffixCopy(threadLocal)\n\n        registerThreadLocalWithShadowCopier(threadLocal, true).shouldBeTrue()\n        // copier changed\n        assertTransmitShadowCopy(threadLocal)\n\n        registerThreadLocal(threadLocal, APPEND_SUFFIX_COPIER).shouldBeFalse()\n        // copier do not change\n        assertTransmitShadowCopy(threadLocal)\n\n        registerThreadLocal(threadLocal, APPEND_SUFFIX_COPIER, true).shouldBeTrue()\n        // copier changed\n        assertTransmitSuffixCopy(threadLocal)\n\n        // Unregister\n        unregisterThreadLocal(threadLocal).shouldBeTrue()\n        assertNotTransmit(threadLocal)\n    }\n\n    private fun assertTransmitSuffixCopy(threadLocal: ThreadLocal<String>) {\n        val future = executorService.submit {\n            threadLocal.get() shouldBe \"$PARENT$COPY_SUFFIX\"\n            threadLocal.set(CHILD)\n        }\n\n        threadLocal.get() shouldBe PARENT\n        future.get(1, TimeUnit.SECONDS)\n    }\n\n    @Test\n    fun test_clear() {\n        val initValue = \"init\"\n\n        val threadLocal = object : ThreadLocal<String>() {\n            override fun initialValue(): String = initValue\n        }\n        threadLocal.get() shouldBe initValue\n        threadLocal.set(PARENT)\n\n        registerThreadLocalWithShadowCopier(threadLocal).shouldBeTrue()\n\n        runCallableWithClear {\n            val future = executorService.submit {\n                threadLocal.get() shouldBe initValue\n                threadLocal.set(CHILD)\n            }\n\n            threadLocal.get() shouldBe initValue\n            future.get(1, TimeUnit.SECONDS)\n        }\n\n        threadLocal.get() shouldBe PARENT\n    }\n\n    @Test\n    fun register_ThreadLocal_can_NOT_Inheritable() {\n        val initValue = \"init\"\n        val threadLocal = object : ThreadLocal<String>() {\n            override fun initialValue(): String = initValue\n        }\n        threadLocal.set(PARENT)\n        registerThreadLocalWithShadowCopier(threadLocal).shouldBeTrue()\n\n        val blockingQueue = LinkedBlockingQueue<String>(1)\n        thread {\n            blockingQueue.add(threadLocal.get())\n        }\n\n        blockingQueue.take() shouldBe initValue\n    }\n\n    @Test\n    fun register_InheritableThreadLocal_can_Inheritable() {\n        val initValue = \"init\"\n        val threadLocal = object : InheritableThreadLocal<String>() {\n            override fun initialValue(): String = initValue\n        }\n        threadLocal.set(PARENT)\n        registerThreadLocalWithShadowCopier(threadLocal).shouldBeTrue()\n\n        val blockingQueue = LinkedBlockingQueue<String>(1)\n        thread {\n            blockingQueue.add(threadLocal.get())\n        }\n\n        blockingQueue.take() shouldBe PARENT\n    }\n\n    @AfterAll\n    fun afterAll() {\n        executorService.shutdown()\n        // Fail to shut down thread pool\n        executorService.awaitTermination(1, TimeUnit.SECONDS).shouldBeTrue()\n    }\n\n    companion object {\n        private val PARENT = \"parent: \" + Date()\n        private val CHILD = \"child: \" + Date()\n        private const val COPY_SUFFIX = \" 42\"\n        private val APPEND_SUFFIX_COPIER = TtlCopier<String> { \"$it$COPY_SUFFIX\" }\n\n        private val executorService: ExecutorService = Executors.newFixedThreadPool(3).let {\n            expandThreadPool(it)\n            TtlExecutors.getTtlExecutorService(it)\n        }!!\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/threadpool/BeforeAndAfterExecuteMethodOfExecutorSubclassTest.kt",
    "content": "@file:Suppress(\"PackageDirectoryMismatch\")\n\n// Change the package out of com.alibaba.ttl\n// so agent will transform MyThreadPoolExecutor\npackage com.alibaba.test.ttl.threadpool\n\nimport com.alibaba.hasTtlAgentRun\nimport com.alibaba.noTtlAgentRun\nimport com.alibaba.ttl.TtlRunnable\nimport com.alibaba.ttl.threadpool.TtlExecutors\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertTrue\nimport org.junit.Test\nimport java.util.concurrent.*\n\nclass MyThreadPoolExecutor(count: Int) : ThreadPoolExecutor(10, 20, 10, TimeUnit.SECONDS, LinkedBlockingQueue()) {\n    val runnableList = CopyOnWriteArrayList<Runnable>()\n    private val countDownLatch = CountDownLatch(count * 2)\n\n    override fun afterExecute(r: Runnable, t: Throwable?) {\n        runnableList.add(r)\n        countDownLatch.countDown()\n        super.afterExecute(r, t)\n    }\n\n    override fun beforeExecute(t: Thread, r: Runnable) {\n        runnableList.add(r)\n        countDownLatch.countDown()\n        super.beforeExecute(t, r)\n    }\n\n    fun await() {\n        countDownLatch.await()\n    }\n}\n\nclass MyRunnable : Runnable {\n    override fun run() {\n        Thread.sleep(1)\n    }\n}\n\nclass BeforeAndAfterExecuteMethodOfExecutorSubclassTest {\n    private val count = 10\n\n    @Test\n    fun underAgent() {\n        if (noTtlAgentRun()) return\n\n        val myThreadPoolExecutor = MyThreadPoolExecutor(count)\n\n        (0 until count).map {\n            myThreadPoolExecutor.execute(MyRunnable())\n        }\n\n        myThreadPoolExecutor.await()\n\n        assertEquals(count * 2, myThreadPoolExecutor.runnableList.size)\n        assertTrue(myThreadPoolExecutor.runnableList.all { it is MyRunnable })\n    }\n\n    /**\n     * for bug submitted by\n     * https://github.com/alibaba/transmittable-thread-local/issues/133#issuecomment-1068793261\n     */\n    @Test\n    fun underAgent_task_is_explicit_TtlRunnable__should_not_be_unwrapped() {\n        if (noTtlAgentRun()) return\n\n        val myThreadPoolExecutor = MyThreadPoolExecutor(count)\n\n        (0 until count).map {\n            val r = TtlRunnable.get(MyRunnable())!!\n            myThreadPoolExecutor.execute(r)\n        }\n\n        myThreadPoolExecutor.await()\n\n        assertEquals(count * 2, myThreadPoolExecutor.runnableList.size)\n        assertTrue(myThreadPoolExecutor.runnableList.all { it is TtlRunnable })\n    }\n\n    @Test\n    fun noAgent_task_is_TtlRunnable() {\n        if (hasTtlAgentRun()) return\n\n        val myThreadPoolExecutor = MyThreadPoolExecutor(count)\n        val ttlExecutorService = TtlExecutors.getTtlExecutorService(myThreadPoolExecutor)!!\n\n        (0 until count).map {\n            ttlExecutorService.execute(MyRunnable())\n        }\n\n        myThreadPoolExecutor.await()\n\n        assertEquals(count * 2, myThreadPoolExecutor.runnableList.size)\n        assertTrue(myThreadPoolExecutor.runnableList.all { it is TtlRunnable })\n    }\n\n    @Test\n    fun noAgent_task_is_NOT_TtlRunnable() {\n        if (hasTtlAgentRun()) return\n\n        val myThreadPoolExecutor = MyThreadPoolExecutor(count)\n\n        (0 until count).map {\n            myThreadPoolExecutor.execute(MyRunnable())\n        }\n\n        myThreadPoolExecutor.await()\n\n        assertEquals(count * 2, myThreadPoolExecutor.runnableList.size)\n        assertTrue(myThreadPoolExecutor.runnableList.all { it is MyRunnable })\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/threadpool/ExecutorClassesTest.kt",
    "content": "package com.alibaba.ttl.threadpool\n\nimport com.alibaba.*\nimport com.alibaba.ttl.TtlRunnable\nimport com.alibaba.ttl.testmodel.Task\nimport org.junit.Assert.assertFalse\nimport org.junit.Assert.assertTrue\nimport org.junit.Test\nimport java.util.concurrent.*\n\nprivate const val POOL_SIZE = 3\n\nval threadFactory = ThreadFactory { Thread(it).apply { isDaemon = true } }\n\nval executorService = ThreadPoolExecutor(\n    POOL_SIZE, POOL_SIZE,\n    10L, TimeUnit.SECONDS,\n    LinkedBlockingQueue(), threadFactory\n)\n\nval scheduledExecutorService = ScheduledThreadPoolExecutor(POOL_SIZE, threadFactory)\n\nclass ExecutorClassesTest {\n    @Test\n    fun checkThreadPoolExecutorForRemoveMethod() {\n        val futures = (0 until POOL_SIZE * 2).map {\n            executorService.submit { Thread.sleep(10) }\n        }\n\n        Runnable {\n            println(\"Task should be removed!\")\n        }.let {\n            if (noTtlAgentRun()) TtlRunnable.get(it) else it\n        }.let {\n            executorService.execute(it)\n            // Does ThreadPoolExecutor#remove method take effect?\n            assertTrue(executorService.remove(it))\n            assertFalse(executorService.remove(it))\n        }\n\n        // wait sleep task finished.\n        futures.forEach { it.get(1, TimeUnit.SECONDS) }\n    }\n\n    @Test\n    fun checkScheduledExecutorService() {\n        val ttlInstances = createParentTtlInstances(ConcurrentHashMap())\n\n        val tag = \"2\"\n        val task = Task(tag, ttlInstances)\n        val future = scheduledExecutorService.schedule(\n            if (noTtlAgentRun()) TtlRunnable.get(task) else task,\n            10,\n            TimeUnit.MILLISECONDS\n        )\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        future.get(1, TimeUnit.SECONDS)\n\n\n        // child Inheritable\n        assertChildTtlValues(tag, task.copied)\n        // child do not affect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/threadpool/ScheduledExecutorServiceTtlWrapperTest.kt",
    "content": "package com.alibaba.ttl.threadpool\n\nimport com.alibaba.*\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.testmodel.Call\nimport com.alibaba.ttl.testmodel.Task\nimport io.kotest.core.spec.style.AnnotationSpec\nimport org.junit.Assert.*\nimport java.util.concurrent.*\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass ScheduledExecutorServiceTtlWrapperTest : AnnotationSpec() {\n\n    private lateinit var ttlInstances: ConcurrentMap<String, TransmittableThreadLocal<String>>\n\n    @Before\n    fun setUp() {\n        ttlInstances = createParentTtlInstances(ConcurrentHashMap())\n    }\n\n    @After\n    fun tearDown() {\n        // child do not affect parent\n        assertParentTtlValues(copyTtlValues(ttlInstances))\n    }\n\n    @Test\n    fun test_execute() {\n        val task = Task(\"1\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        executorService.execute(task)\n\n        // child Inheritable\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", task.copied)\n    }\n\n    @Test\n    fun test_submit() {\n        val call = Call(\"1\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        val future = executorService.submit(call)\n        assertEquals(\"ok\", future.get())\n\n        // child Inheritable\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", call.copied)\n    }\n\n    @Test\n    fun test_submit_runnable_result() {\n        val task = Task(\"1\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        val future = executorService.submit(task, \"ok\")\n        assertEquals(\"ok\", future.get())\n\n        // child Inheritable\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", task.copied)\n    }\n\n    @Test\n    fun test_submit_runnable_null() {\n        val task = Task(\"1\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        val future = executorService.submit(task)\n        assertNull(future.get())\n\n        // child Inheritable\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", task.copied)\n    }\n\n    @Test\n    fun test_invokeAll() {\n        val call1 = Call(\"1\", ttlInstances)\n        val call2 = Call(\"2\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        val futures = executorService.invokeAll(listOf(call1, call2))\n        for (future in futures) {\n            assertEquals(\"ok\", future.get())\n        }\n\n        // child Inheritable\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", call1.copied)\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"2\", call2.copied)\n    }\n\n    @Test\n    fun test_invokeAll_timeout() {\n        val call1 = Call(\"1\", ttlInstances)\n        val call2 = Call(\"2\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        val futures = executorService.invokeAll(listOf(call1, call2), 1, TimeUnit.SECONDS)\n        for (future in futures) {\n            assertEquals(\"ok\", future.get())\n        }\n\n        // child Inheritable\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", call1.copied)\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"2\", call2.copied)\n    }\n\n    @Test\n    fun test_invokeAny() {\n        val call1 = Call(\"1\", ttlInstances)\n        val call2 = Call(\"2\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        val s = executorService.invokeAny(listOf(call1, call2))\n        assertEquals(\"ok\", s)\n\n        assertTrue(call1.isCopied || call2.isCopied)\n        if (call1.isCopied)\n        // child Inheritable\n            assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", call1.copied)\n        if (call2.isCopied)\n            assertChildTtlValuesWithParentCreateAfterCreateChild(\"2\", call2.copied)\n    }\n\n    @Test\n    fun test_invokeAny_timeout() {\n        val call1 = Call(\"1\", ttlInstances)\n        val call2 = Call(\"2\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        val s = executorService.invokeAny(listOf(call1, call2), 1, TimeUnit.SECONDS)\n        assertEquals(\"ok\", s)\n\n        assertTrue(call1.isCopied || call2.isCopied)\n\n        if (call1.isCopied)\n        // child Inheritable\n            assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", call1.copied)\n        if (call2.isCopied)\n            assertChildTtlValuesWithParentCreateAfterCreateChild(\"2\", call2.copied)\n    }\n\n    @Test\n    fun test_schedule_runnable() {\n        val task = Task(\"1\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        val future = executorService.schedule(task, 100, TimeUnit.MILLISECONDS)\n        assertNull(future.get())\n\n        // child Inheritable\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", task.copied)\n    }\n\n    @Test\n    fun test_schedule_callable() {\n        val call = Call(\"1\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n        val future = executorService.schedule(call, 100, TimeUnit.MILLISECONDS)\n        assertEquals(\"ok\", future.get())\n\n        // child Inheritable\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", call.copied)\n    }\n\n    @Test\n    fun test_scheduleAtFixedRate() {\n        val task = Task(\"1\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n        val future = executorService.scheduleAtFixedRate(task, 0, 10, TimeUnit.SECONDS)\n        Thread.sleep(10)\n        future.cancel(true)\n\n        // child Inheritable\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", task.copied)\n    }\n\n    @Test\n    fun test_scheduleWithFixedDelay() {\n        val task = Task(\"1\", ttlInstances)\n\n        // create after new Task, won't see parent value in in task!\n        createParentTtlInstancesAfterCreateChild(ttlInstances)\n\n\n        val future = executorService.scheduleWithFixedDelay(task, 0, 10, TimeUnit.SECONDS)\n\n        Thread.sleep(10)\n        future.cancel(true)\n\n        // child Inheritable\n        assertChildTtlValuesWithParentCreateAfterCreateChild(\"1\", task.copied)\n    }\n\n    @AfterAll\n    fun afterAll() {\n        executorService.shutdown()\n        assertTrue(\"Fail to shutdown thread pool\", executorService.awaitTermination(1, TimeUnit.SECONDS))\n    }\n\n    companion object {\n        private val executorService: ScheduledExecutorService = ScheduledThreadPoolExecutor(3).let {\n            it.setKeepAliveTime(10, TimeUnit.SECONDS)\n            expandThreadPool(it)\n            TtlExecutors.getTtlScheduledExecutorService(it)\n        }!!\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/threadpool/TtlExecutorsTest.kt",
    "content": "package com.alibaba.ttl.threadpool\n\nimport com.alibaba.hasTtlAgentRun\nimport com.alibaba.noTtlAgentRun\nimport com.alibaba.ttl.TtlCallable\nimport com.alibaba.ttl.TtlRunnable\nimport com.alibaba.ttl.TtlUnwrap\nimport com.alibaba.ttl.threadpool.TtlExecutors.*\nimport io.kotest.assertions.throwables.shouldThrow\nimport io.kotest.assertions.withClue\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.string.shouldContain\nimport org.junit.Assert.*\nimport java.util.concurrent.*\nimport java.util.concurrent.Executors.newScheduledThreadPool\nimport java.util.concurrent.atomic.AtomicInteger\n\n/**\n * @author Jerry Lee (oldratlee at gmail dot com)\n */\nclass TtlExecutorsTest : AnnotationSpec() {\n\n    ///////////////////////////////////////////////\n    // test getTtl*ExecutorService\n    ///////////////////////////////////////////////\n\n    @Test\n    fun test_getTtlExecutorService__common() {\n        val newScheduledThreadPool = newScheduledThreadPool(3)\n\n        getTtlExecutor(newScheduledThreadPool).let {\n            if (noTtlAgentRun()) assertTrue(it is ExecutorTtlWrapper)\n            assertEquals(noTtlAgentRun(), isTtlWrapper(it))\n\n            assertSame(newScheduledThreadPool, unwrap(it))\n            assertSame(newScheduledThreadPool, TtlUnwrap.unwrap(it))\n        }\n        getTtlExecutorService(newScheduledThreadPool).let {\n            if (noTtlAgentRun()) assertTrue(it is ExecutorServiceTtlWrapper)\n            assertEquals(noTtlAgentRun(), isTtlWrapper(it))\n\n            assertSame(newScheduledThreadPool, unwrap(it))\n            assertSame(newScheduledThreadPool, TtlUnwrap.unwrap(it))\n        }\n        getTtlScheduledExecutorService(newScheduledThreadPool).let {\n            if (noTtlAgentRun()) assertTrue(it is ScheduledExecutorServiceTtlWrapper)\n            assertEquals(noTtlAgentRun(), isTtlWrapper(it))\n\n            assertSame(newScheduledThreadPool, unwrap(it))\n            assertSame(newScheduledThreadPool, TtlUnwrap.unwrap(it))\n        }\n\n        newScheduledThreadPool.shutdown()\n    }\n\n    @Test\n    fun test_getTtlExecutorService__null() {\n        assertNull(getTtlExecutor(null))\n        assertNull(getTtlExecutorService(null))\n        assertNull(getTtlScheduledExecutorService(null))\n\n        assertFalse(isTtlWrapper(null))\n        assertNull(unwrap<Executor>(null))\n    }\n\n    @Test\n    fun test_getTtlExecutorService_is__idempotent() {\n        val newScheduledThreadPool = newScheduledThreadPool(3)\n\n        getTtlExecutor(newScheduledThreadPool)!!.let {\n            assertSame(it, getTtlExecutor(it))\n\n            it.execute(TtlRunnable.get { }!!)\n        }\n\n        getTtlExecutorService(newScheduledThreadPool)!!.let {\n            assertSame(it, getTtlExecutorService(it))\n\n            it.submit(TtlCallable.get { 42 }!!).get()\n            it.submit(TtlRunnable.get { }!!, 42).get()\n            it.submit(TtlRunnable.get { }!!).get()\n\n            it.invokeAll(listOf(TtlCallable.get { 42 }!!)).map { f -> f.get() }\n            it.invokeAll(listOf(TtlCallable.get { 42 }!!), 1, TimeUnit.SECONDS).map { f -> f.get() }\n\n            it.invokeAny(listOf(TtlCallable.get { 42 }!!))\n            it.invokeAny(listOf(TtlCallable.get { 42 }!!), 1, TimeUnit.SECONDS)\n        }\n\n        getTtlScheduledExecutorService(newScheduledThreadPool)!!.let {\n            assertSame(it, getTtlScheduledExecutorService(it))\n\n            it.schedule(TtlRunnable.get { }!!, 1, TimeUnit.MICROSECONDS).get()\n            it.schedule(TtlCallable.get { 42 }!!, 1, TimeUnit.MICROSECONDS).get()\n\n            it.scheduleAtFixedRate(TtlRunnable.get { }!!, 0, 1, TimeUnit.MICROSECONDS).cancel(true)\n            it.scheduleWithFixedDelay(TtlRunnable.get { }!!, 0, 1, TimeUnit.MICROSECONDS).cancel(true)\n        }\n\n        newScheduledThreadPool.shutdown()\n    }\n\n    ///////////////////////////////////////////////\n    // test getDisableInheritableThreadFactory\n    ///////////////////////////////////////////////\n\n    @Test\n    fun test_getDisableInheritableThreadFactory__common() {\n        val threadFactory = ThreadFactory { Thread(it) }\n        getDisableInheritableThreadFactory(threadFactory).let {\n            assertTrue(it is DisableInheritableThreadFactory)\n            assertTrue(isDisableInheritableThreadFactory(it))\n\n            assertSame(threadFactory, unwrap(it))\n            assertSame(threadFactory, TtlUnwrap.unwrap(it))\n        }\n    }\n\n    @Test\n    @Suppress(\"CAST_NEVER_SUCCEEDS\")\n    fun test_getDisableInheritableThreadFactory__null() {\n        assertNull(getDisableInheritableThreadFactory(null))\n        assertFalse(isDisableInheritableThreadFactory(null))\n        assertNull(unwrap(null as? ThreadFactory))\n    }\n\n    @Test\n    fun test_getDisableInheritableThreadFactory__is_idempotent() {\n        val threadFactory = ThreadFactory { Thread(it) }\n\n        val disableInheritableThreadFactory = getDisableInheritableThreadFactory(threadFactory)\n        assertSame(disableInheritableThreadFactory, getDisableInheritableThreadFactory(disableInheritableThreadFactory))\n    }\n\n    ///////////////////////////////////////////////\n    // test getTtlRunnableUnwrapComparator\n    ///////////////////////////////////////////////\n\n    @Test\n    fun test_getTtlRunnableUnwrapComparator__common() {\n        val comparator: Comparator<Runnable> =\n            Comparator { _, _ -> throw NotImplementedError(\"An operation is not implemented\") }\n\n        getTtlRunnableUnwrapComparator(comparator).let {\n            // use class name check instead of type check by\n            //     assertTrue(it is TtlUnwrapComparator)\n            //\n            // avoid test error under java 11 using TTL Agent:\n            //\n            // java.lang.IllegalAccessError:\n            //   failed to access class com.alibaba.ttl.threadpool.TtlUnwrapComparator\n            //     from class com.alibaba.ttl.threadpool.TtlExecutorsTest\n            //   (com.alibaba.ttl.threadpool.TtlUnwrapComparator is in unnamed module of loader 'bootstrap';\n            //     com.alibaba.ttl.threadpool.TtlExecutorsTest is in unnamed module of loader 'app')\n            assertEquals(\"com.alibaba.ttl.threadpool.TtlUnwrapComparator\", it!!.javaClass.name)\n\n            assertTrue(isTtlRunnableUnwrapComparator(it))\n\n            assertSame(comparator, unwrap(it))\n            assertSame(comparator, TtlUnwrap.unwrap(it))\n        }\n    }\n\n    @Test\n    @Suppress(\"CAST_NEVER_SUCCEEDS\")\n    fun test_getTtlRunnableUnwrapComparator__null() {\n        assertNull(getTtlRunnableUnwrapComparator(null))\n        assertFalse(isTtlRunnableUnwrapComparator(null))\n        assertNull(unwrap(null as? java.util.Comparator<Runnable>))\n    }\n\n    @Test\n    fun test_getTtlRunnableUnwrapComparator__is_idempotent() {\n        val comparator: Comparator<Runnable> =\n            Comparator { _, _ -> throw NotImplementedError(\"An operation is not implemented\") }\n\n        val ttlRunnableUnwrapComparator = getTtlRunnableUnwrapComparator(comparator)\n        assertSame(ttlRunnableUnwrapComparator, getTtlRunnableUnwrapComparator(ttlRunnableUnwrapComparator))\n    }\n\n    /**\n     * https://github.com/alibaba/transmittable-thread-local/issues/330\n     */\n    @Test\n    fun test_reproduce_ClassCastException_of_issue_330() {\n        if (hasTtlAgentRun()) return\n\n        val priorityBlockingQueue = PriorityBlockingQueue<Runnable>()\n\n        Pair(\n            BizComparableTask().also { priorityBlockingQueue.put(it) },\n            BizComparableTask().also { priorityBlockingQueue.put(it) },\n        ).let { (task0, task1) ->\n            assertEquals(task0, priorityBlockingQueue.poll())\n            assertEquals(task1, priorityBlockingQueue.poll())\n        }\n\n        BizComparableTask().also { priorityBlockingQueue.put(it) }\n\n\n        val exception = shouldThrow<ClassCastException> {\n            val task = BizComparableTask()\n            priorityBlockingQueue.put(TtlRunnable.get(task)!!)\n        }\n        assertClassCastException(exception, TtlRunnable::class.java, Comparable::class.java)\n    }\n\n    @Test\n    fun test_fixed_ClassCastException_of_issue_330() {\n        val priorityBlockingQueue: BlockingQueue<Runnable> = if (noTtlAgentRun()) {\n            // explicit PriorityBlockingQueue arguments\n            PriorityBlockingQueue(11, getTtlRunnableUnwrapComparatorForComparableRunnable())\n        } else {\n            // No PriorityBlockingQueue arguments\n            PriorityBlockingQueue()\n        }\n\n        Pair(\n            BizComparableTask().also { priorityBlockingQueue.put(it) },\n            BizComparableTask().let { TtlRunnable.get(it) }!!.also { priorityBlockingQueue.put(it) },\n        ).let { (task0, task1) ->\n            assertEquals(task0, priorityBlockingQueue.poll())\n            assertEquals(task1, priorityBlockingQueue.poll())\n        }\n    }\n\n    @Test\n    fun test_reproduce_ClassCastException_explicit_comparator() {\n        if (hasTtlAgentRun()) return\n\n        val priorityBlockingQueue = PriorityBlockingQueue(11, compareBy<Runnable> { (it as BizOrderTask).order })\n\n        Pair(\n            BizOrderTask(1).also { priorityBlockingQueue.put(it) },\n            BizOrderTask(2).also { priorityBlockingQueue.put(it) },\n        ).let { (task0, task1) ->\n            assertEquals(task0, priorityBlockingQueue.poll())\n            assertEquals(task1, priorityBlockingQueue.poll())\n        }\n\n        BizOrderTask(3).also { priorityBlockingQueue.put(it) }\n\n\n        val exception = shouldThrow<ClassCastException> {\n            val task = BizOrderTask(4)\n            priorityBlockingQueue.put(TtlRunnable.get(task)!!)\n        }\n        assertClassCastException(exception, TtlRunnable::class.java, BizOrderTask::class.java)\n    }\n\n    @Test\n    fun test_fixed_ClassCastException_explicit_comparator() {\n        val priorityBlockingQueue = PriorityBlockingQueue(11,\n            compareBy<Runnable> { (it as BizOrderTask).order }.let {\n                if (noTtlAgentRun()) getTtlRunnableUnwrapComparator(it)\n                else it\n            }\n        )\n\n        Pair(\n            BizOrderTask(1).also { priorityBlockingQueue.put(it) },\n            BizOrderTask(2).let { TtlRunnable.get(it) }.also { priorityBlockingQueue.put(it) },\n        ).let { (task0, task1) ->\n            assertEquals(task0, priorityBlockingQueue.poll())\n            assertEquals(task1, priorityBlockingQueue.poll())\n        }\n    }\n\n    private fun assertClassCastException(e: ClassCastException, actualClass: Class<*>, targetClass: Class<*>) {\n        withClue(\"ClassCastException.message: ${e.message}\") {\n            e.message shouldContain actualClass.name\n            e.message shouldContain targetClass.name\n        }\n    }\n\n    /**\n     * https://github.com/alibaba/transmittable-thread-local/issues/361\n     */\n    @Test\n    fun test_fixed_ClassCastException_of_issue_361() {\n        val queue = PriorityBlockingQueue<Int>()\n        queue.put(1)\n        queue.put(100)\n        queue.put(2)\n\n        assertEquals(1, queue.poll())\n        assertEquals(2, queue.poll())\n        assertEquals(100, queue.poll())\n    }\n}\n\nprivate class BizComparableTask : Runnable, Comparable<Runnable> {\n    companion object {\n        val counter = AtomicInteger()\n    }\n\n    private val num = counter.getAndIncrement()\n\n    override fun run() {\n        println(\"BizComparableTask#run\")\n    }\n\n    override fun compareTo(other: Runnable): Int = num - (other as BizComparableTask).num\n}\n\nprivate data class BizOrderTask(val order: Int) : Runnable {\n    override fun run() {\n        println(\"BizOrderTask#run\")\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/threadpool/TtlForkJoinPoolHelperTest.kt",
    "content": "package com.alibaba.ttl.threadpool\n\nimport com.alibaba.ttl.TtlUnwrap\nimport io.kotest.core.spec.style.AnnotationSpec\nimport org.junit.Assert.*\nimport java.util.concurrent.ForkJoinPool\n\nclass TtlForkJoinPoolHelperTest : AnnotationSpec() {\n    @Test\n    fun test_DisableInheritableForkJoinWorkerThreadFactory() {\n        TtlForkJoinPoolHelper.getDefaultDisableInheritableForkJoinWorkerThreadFactory().let {\n            assertTrue(it is DisableInheritableForkJoinWorkerThreadFactory)\n            assertTrue(TtlForkJoinPoolHelper.isDisableInheritableForkJoinWorkerThreadFactory(it))\n\n            assertSame(ForkJoinPool.defaultForkJoinWorkerThreadFactory, TtlForkJoinPoolHelper.unwrap(it))\n            assertSame(ForkJoinPool.defaultForkJoinWorkerThreadFactory, TtlUnwrap.unwrap(it))\n        }\n    }\n\n    @Test\n    fun test_null() {\n        assertFalse(TtlForkJoinPoolHelper.isDisableInheritableForkJoinWorkerThreadFactory(null))\n        assertNull(TtlForkJoinPoolHelper.unwrap(null))\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/threadpool/agent/TtlAgentHelperTest.kt",
    "content": "package com.alibaba.ttl.threadpool.agent\n\nimport com.alibaba.ttl.threadpool.agent.TtlAgentHelper.*\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.core.test.config.TestCaseConfig\nimport io.kotest.matchers.collections.shouldBeEmpty\nimport io.kotest.matchers.collections.shouldContainExactly\nimport io.kotest.matchers.maps.shouldBeEmpty\nimport io.kotest.matchers.shouldBe\nimport org.junit.Assert.*\n\nclass TtlAgentHelperTest : AnnotationSpec() {\n    @Suppress(\"OVERRIDE_DEPRECATION\")\n    override fun defaultTestCaseConfig(): TestCaseConfig =\n        TestCaseConfig(enabled = !TtlAgent.isTtlAgentLoaded())\n\n    @Test\n    fun test_isBooleanOptionSet() {\n\n        // === test with KV config only  ===\n\n        val kvs = mapOf(\n            \"ttl.test.bool_k1\" to \"true\",\n            \"ttl.test.bool_k2\" to \"false\",\n            \"ttl.test.bool_k3\" to \"\" // value absent\n            // ttl.test.notExisted : key absent\n        )\n\n        kvs.keys.forEach {\n            System.clearProperty(it)\n        }\n        System.clearProperty(\"ttl.test.notExisted\")\n\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.bool_k1\", false))\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.bool_k1\", true))\n\n        assertFalse(isBooleanOptionSet(kvs, \"ttl.test.bool_k2\", true))\n        assertFalse(isBooleanOptionSet(kvs, \"ttl.test.bool_k2\", false))\n\n        // bool_k3 is *value absent*, IS true\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.bool_k3\", true))\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.bool_k3\", false))\n\n        // notExisted is *key absent*, use defaultValueIfKeyAbsent\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.notExisted\", true))\n        assertFalse(isBooleanOptionSet(kvs, \"ttl.test.notExisted\", false))\n\n\n        // === test with -D properties override ===\n\n        // override with -D properties value\n        System.setProperty(\"ttl.test.bool_k1\", \"false\")\n\n        assertFalse(isBooleanOptionSet(kvs, \"ttl.test.bool_k1\", false))\n        assertFalse(isBooleanOptionSet(kvs, \"ttl.test.bool_k1\", true))\n\n        // override with -D properties empty value, IS true\n        System.setProperty(\"ttl.test.bool_k2\", \"\")\n\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.bool_k2\", true))\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.bool_k2\", false))\n\n\n        // === test with -D properties config only  ===\n\n        mapOf(\n            \"ttl.test.property_only.bool_k1\" to \"true\",\n            \"ttl.test.property_only.bool_k2\" to \"false\",\n            \"ttl.test.property_only.bool_k3\" to \"\" // value absent\n            // ttl.test.property_only.notExisted : key absent\n        ).forEach { (k, v) -> System.setProperty(k, v) }\n        System.clearProperty(\"ttl.test.property_only.notExisted\")\n\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.property_only.bool_k1\", false))\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.property_only.bool_k1\", true))\n\n        assertFalse(isBooleanOptionSet(kvs, \"ttl.test.property_only.bool_k2\", true))\n        assertFalse(isBooleanOptionSet(kvs, \"ttl.test.property_only.bool_k2\", false))\n\n        // bool_k3 is *value absent*, IS true\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.property_only.bool_k3\", true))\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.property_only.bool_k3\", false))\n\n        // notExisted is *key absent*, use defaultValueIfKeyAbsent\n        assertTrue(isBooleanOptionSet(kvs, \"ttl.test.property_only.notExisted\", true))\n        assertFalse(isBooleanOptionSet(kvs, \"ttl.test.property_only.notExisted\", false))\n    }\n\n    @Test\n    fun test_getOptionStringListValues() {\n\n        // === test with KV config only  ===\n\n        val kvs = mapOf(\n            \"ttl.test.str_k1\" to \"value1\",\n            \"ttl.test.str_k2\" to \"\" // value absent\n            // ttl.test.notExisted : key absent\n        )\n\n        kvs.keys.forEach {\n            System.clearProperty(it)\n        }\n        System.clearProperty(\"ttl.test.notExisted\")\n\n        assertEquals(\"value1\", getStringOptionValue(kvs, \"ttl.test.str_k1\", \"default_value\"))\n        // str_k2 is *value absent*, use default value\n        assertEquals(\"default_value\", getStringOptionValue(kvs, \"ttl.test.str_k2\", \"default_value\"))\n        // notExisted is *key absent*, use default value\n        assertEquals(\"default_value\", getStringOptionValue(kvs, \"ttl.test.notExisted\", \"default_value\"))\n\n\n        // === test with -D properties override ===\n\n        // override with -D properties value\n        System.setProperty(\"ttl.test.str_k1\", \"value2\")\n        assertEquals(\"value2\", getStringOptionValue(kvs, \"ttl.test.str_k1\", \"default_value\"))\n\n        // override with -D properties empty value, use default value\n        System.setProperty(\"ttl.test.str_k1\", \"\")\n        assertEquals(\"default_value\", getStringOptionValue(kvs, \"ttl.test.str_k1\", \"default_value\"))\n\n\n        // === test with -D properties config only ===\n\n        mapOf(\n            \"ttl.test.property_only.str_k1\" to \"value1\",\n            \"ttl.test.property_only.str_k2\" to \"\" // value absent\n            // ttl.test.property_only.notExisted : key absent\n        ).forEach { (k, v) -> System.setProperty(k, v) }\n        System.clearProperty(\"ttl.test.property_only.notExisted\")\n\n\n        assertEquals(\"value1\", getStringOptionValue(kvs, \"ttl.test.property_only.str_k1\", \"default_value\"))\n        // str_k2 is *value absent*, use default value\n        assertEquals(\"default_value\", getStringOptionValue(kvs, \"ttl.test.property_only.str_k2\", \"default_value\"))\n        // str_k2 is *key absent*, use default value\n        assertEquals(\"default_value\", getStringOptionValue(kvs, \"ttl.test.property_only.notExisted\", \"default_value\"))\n    }\n\n    @Test\n    fun test_splitCommaColonStringToKV() {\n        splitCommaColonStringToKV(null).shouldBeEmpty()\n        splitCommaColonStringToKV(\"\").shouldBeEmpty()\n        splitCommaColonStringToKV(\"   \").shouldBeEmpty()\n\n        splitCommaColonStringToKV(\"k1,k2\") shouldBe mapOf(\"k1\" to \"\", \"k2\" to \"\")\n\n        splitCommaColonStringToKV(\"   k1,   k2 \") shouldBe mapOf(\"k1\" to \"\", \"k2\" to \"\")\n\n        splitCommaColonStringToKV(\"ttl.agent.logger:STDOUT\") shouldBe mapOf(\"ttl.agent.logger\" to \"STDOUT\")\n        splitCommaColonStringToKV(\"k1:v1,ttl.agent.logger:STDOUT\") shouldBe\n                mapOf(\"k1\" to \"v1\", \"ttl.agent.logger\" to \"STDOUT\")\n\n\n        splitCommaColonStringToKV(\"     k1     :v1  , ttl.agent.logger    :STDOUT   \") shouldBe\n                mapOf(\"k1\" to \"v1\", \"ttl.agent.logger\" to \"STDOUT\")\n\n        splitCommaColonStringToKV(\"     k1     :v1  , ttl.agent.logger    :STDOUT   ,k3\") shouldBe\n                mapOf(\"k1\" to \"v1\", \"ttl.agent.logger\" to \"STDOUT\", \"k3\" to \"\")\n    }\n\n    @Test\n    fun test_splitListStringToStringList() {\n        splitListStringToStringList(null).shouldBeEmpty()\n        splitListStringToStringList(\"\").shouldBeEmpty()\n        splitListStringToStringList(\"   \").shouldBeEmpty()\n        splitListStringToStringList(\"   |\").shouldBeEmpty()\n        splitListStringToStringList(\"   |  \").shouldBeEmpty()\n        splitListStringToStringList(\"   | | \").shouldBeEmpty()\n\n        splitListStringToStringList(\"v1|v2\")\n            .shouldContainExactly(\"v1\", \"v2\")\n        splitListStringToStringList(\"  v1|v2  |v3  \")\n            .shouldContainExactly(\"v1\", \"v2\", \"v3\")\n\n        splitListStringToStringList(\"com.alibaba.ttl.TtlExecutorTransformlet\")\n            .shouldContainExactly(\"com.alibaba.ttl.TtlExecutorTransformlet\")\n\n        splitListStringToStringList(\"com.alibaba.ttl.TtlExecutorTransformlet|com.alibaba.ttl.TtlForkJoinTransformlet|v3\")\n            .shouldContainExactly(\n                \"com.alibaba.ttl.TtlExecutorTransformlet\",\n                \"com.alibaba.ttl.TtlForkJoinTransformlet\",\n                \"v3\"\n            )\n\n        splitListStringToStringList(\"  com.alibaba.ttl.TtlExecutorTransformlet|  com.alibaba.ttl.TtlForkJoinTransformlet   |v3  \")\n            .shouldContainExactly(\n                \"com.alibaba.ttl.TtlExecutorTransformlet\",\n                \"com.alibaba.ttl.TtlForkJoinTransformlet\",\n                \"v3\"\n            )\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/threadpool/agent/TtlExtensionTransformletManagerTest.kt",
    "content": "package com.alibaba.ttl.threadpool.agent\n\nimport com.alibaba.noTtlAgentRun\nimport com.alibaba.ttl.threadpool.agent.logging.Logger\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.core.test.config.TestCaseConfig\nimport org.junit.Assert.assertEquals\n\nclass TtlExtensionTransformletManagerTest : AnnotationSpec() {\n    @Suppress(\"OVERRIDE_DEPRECATION\")\n    override fun defaultTestCaseConfig(): TestCaseConfig =\n        TestCaseConfig(enabled = noTtlAgentRun())\n\n    @Test\n    fun test_readLines() {\n        val classLoader = TtlExtensionTransformletManagerTest::class.java.classLoader\n        val pair = TtlExtensionTransformletManager.readLinesFromExtensionFiles(\n            classLoader.getResources(\"test_extension/foo.txt\"), mutableMapOf()\n        )\n        val lines: LinkedHashSet<String> = pair.first\n\n        assertEquals(\n            linkedSetOf(\"hello.World\", \"hello.tabBefore\", \"hello.tabAfter\", \"hello.spaceBefore\", \"hello.spaceAfter\"),\n            lines\n        )\n    }\n\n    @BeforeAll\n    fun beforeAll() {\n        Logger.setLoggerImplTypeIfNotSetYet(\"stderr\")\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/threadpool/agent/transformlet/helper/TtlTransformletHelperTest.kt",
    "content": "package com.alibaba.ttl.threadpool.agent.transformlet.helper\n\nimport com.alibaba.ttl.threadpool.agent.TtlAgent\nimport com.alibaba.ttl.threadpool.agent.logging.Logger\nimport com.alibaba.ttl.threadpool.agent.transformlet.helper.TtlTransformletHelper.*\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.matchers.nulls.shouldBeNull\nimport io.kotest.matchers.string.shouldContain\nimport io.kotest.matchers.string.shouldEndWith\nimport javassist.ClassPool\nimport org.apache.commons.lang3.StringUtils\nimport org.junit.Assert.*\n\nclass TtlTransformletHelperTest : AnnotationSpec() {\n\n    @Test\n    fun test_getFileLocationOfClass_javaClass() {\n\n        getLocationFileOfClass(String::class.java).shouldBeNull()\n\n        val locationFileOfClass = getLocationFileOfClass(StringUtils::class.java)\n        locationFileOfClass shouldEndWith \".jar\"\n        locationFileOfClass shouldContain \"/commons-lang3-\"\n    }\n\n    @Test\n    fun test_getFileLocationOfClass_ctClass() {\n        if (TtlAgent.isTtlAgentLoaded()) return\n\n        val classPool = ClassPool(true)\n\n        // Java 8: file:/path/to/jdk_8/jre/lib/rt.jar!/java/lang/String.class\n        // Java 11: /java.base/java/lang/String.class\n        getLocationFileOfClass(classPool.getCtClass(\"java.lang.String\"))\n            .shouldEndWith(\"/java/lang/String.class\")\n\n        // Java 8: file:/path/to/commons-lang3-3.5.jar!/org/apache/commons/lang3/StringUtils.class\n        val locationFileOfClass = getLocationFileOfClass(classPool.getCtClass(\"org.apache.commons.lang3.StringUtils\"))\n        locationFileOfClass shouldEndWith \".jar!/org/apache/commons/lang3/StringUtils.class\"\n        locationFileOfClass shouldContain \"/commons-lang3-\"\n    }\n\n    @Test\n    fun test_className_package() {\n        assertEquals(\"\", getPackageName(\"Hello\"))\n        assertEquals(\"com.foo\", getPackageName(\"com.foo.Hello\"))\n\n        assertTrue(isClassAtPackage(\"java.util.TimerTask\", \"java.util\"))\n        assertFalse(isClassAtPackage(\"java.util.TimerTask\", \"java.utils\"))\n        assertFalse(isClassAtPackage(\"java.util.TimerTask\", \"java\"))\n        assertFalse(isClassAtPackage(\"java.util.TimerTask\", \"java.util.zip\"))\n\n        assertTrue(isClassUnderPackage(\"java.util.TimerTask\", \"java.util\"))\n        assertFalse(isClassUnderPackage(\"java.util.TimerTask\", \"java.utils\"))\n        assertTrue(isClassUnderPackage(\"java.util.TimerTask\", \"java\"))\n        assertFalse(isClassUnderPackage(\"java.util.TimerTask\", \"javax\"))\n\n        assertTrue(isClassAtPackageJavaUtil(\"java.util.PriorityQueue\"))\n        assertFalse(isClassAtPackageJavaUtil(\"java.util.zip.ZipInputStream\"))\n    }\n\n    @BeforeAll\n    fun beforeClass() {\n        Logger.setLoggerImplTypeIfNotSetYet(\"stderr\")\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/ttl/threadpool/agent/transformlet/internal/UtilsTest.java",
    "content": "package com.alibaba.ttl.threadpool.agent.transformlet.internal;\n\nimport org.junit.Test;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport static org.junit.Assert.fail;\n\npublic class UtilsTest {\n    @Test\n    public void test_get_unboxing_boolean_fromMap() {\n        Map<String, Object> map = new HashMap<>();\n\n        try {\n            getUnboxingBoolean(map, \"not_existed\");\n            fail();\n        } catch (NullPointerException expected) {\n            // do nothing\n        }\n    }\n\n    private static boolean getUnboxingBoolean(Map<String, Object> map, String key) {\n        return (Boolean) map.get(key);\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/user_api_test/README.md",
    "content": "User API Test Cases\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/user_api_test/ttl/DisableIgnoreNullValueSemanticsTest.kt",
    "content": "package com.alibaba.user_api_test.ttl\n\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertNull\nimport org.junit.Test\nimport java.util.concurrent.FutureTask\nimport java.util.concurrent.atomic.AtomicInteger\nimport kotlin.concurrent.thread\n\n/**\n * Test the \"Ignore-Null-Value Semantics\" of [TransmittableThreadLocal] from user code(different package)\n */\nclass DisableIgnoreNullValueSemanticsTest {\n    @Test\n    fun test_TTL_not_disableIgnoreNullValueSemantics_defaultTtlBehavior() {\n        val ttl = object : TransmittableThreadLocal<String?>() {\n            override fun initialValue(): String {\n                return \"init\"\n            }\n\n            override fun childValue(parentValue: String?): String {\n                return \"$parentValue + child\"\n            }\n        }\n\n        assertEquals(\"init\", ttl.get())\n        ttl.set(null)\n        // DO NOT `ttl.get()` !\n        //   `get` operation will re-init the value of ThreadLocal\n\n        val task = FutureTask {\n            ttl.get()\n        }\n        thread { task.run() }.join()\n\n        // `get` operation will re-init the value of ThreadLocal !\n        assertEquals(\"init\", ttl.get())\n        // \"Ignore-Null-Value Semantics\" will not transmit ThreadLocal with the null value,\n        // so the value in new thread is \"init\" value\n        assertEquals(\"init\", task.get())\n\n        //////////////////////////////////////\n\n        val task2 = FutureTask {\n            ttl.get()\n        }\n        thread { task2.run() }.join()\n\n        assertEquals(\"init\", ttl.get())\n        assertEquals(\"init + child\", task2.get())\n    }\n\n    @Test\n    fun test_TTL_not_disableIgnoreNullValueSemantics_defaultTtlBehavior_getSafe_ForNullInit() {\n        val count = AtomicInteger()\n\n        val ttl = object : TransmittableThreadLocal<String?>() {\n            override fun initialValue(): String? {\n                count.getAndIncrement()\n                return super.initialValue()\n            }\n\n            override fun childValue(parentValue: String?): String? {\n                count.getAndSet(1000)\n                return super.childValue(parentValue)\n            }\n        }\n\n        assertNull(ttl.get())\n        assertEquals(1, count.get())\n\n        ttl.set(null)\n        assertNull(ttl.get())\n        assertEquals(2, count.get())\n    }\n\n    @Test\n    fun test_TTL_disableIgnoreNullValueSemantics_sameAsThreadLocal() {\n        val ttl = object : TransmittableThreadLocal<String?>(true) {\n            override fun initialValue(): String {\n                return \"init\"\n            }\n\n            override fun childValue(parentValue: String?): String {\n                return \"$parentValue + child\"\n            }\n        }\n\n        assertEquals(\"init\", ttl.get())\n        ttl.set(null)\n        assertNull(ttl.get())\n\n        val task = FutureTask {\n            ttl.get()\n        }\n        thread { task.run() }.join()\n\n        assertNull(ttl.get())\n        assertEquals(\"null + child\", task.get())\n\n        //////////////////////////////////////\n\n        val task2 = FutureTask {\n            ttl.get()\n        }\n        thread { task2.run() }.join()\n\n        assertNull(ttl.get())\n        assertEquals(\"null + child\", task.get())\n    }\n\n    @Test\n    fun test_InheritableThreadLocal() {\n        val ttl = object : InheritableThreadLocal<String?>() {\n            override fun initialValue(): String {\n                return \"init\"\n            }\n\n            override fun childValue(parentValue: String?): String {\n                return \"$parentValue + child\"\n            }\n        }\n\n        assertEquals(\"init\", ttl.get())\n        ttl.set(null)\n        assertNull(ttl.get())\n\n        val task = FutureTask {\n            ttl.get()\n        }\n        thread { task.run() }.join()\n\n        assertNull(ttl.get())\n        assertEquals(\"null + child\", task.get())\n\n        //////////////////////////////////////\n\n        val task2 = FutureTask {\n            ttl.get()\n        }\n        thread { task2.run() }.join()\n\n        assertNull(ttl.get())\n        assertEquals(\"null + child\", task.get())\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/user_api_test/ttl/TransmittableThreadLocal_Transmitter_UserTest.kt",
    "content": "package com.alibaba.user_api_test.ttl\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.TransmittableThreadLocal.Transmitter\nimport io.kotest.core.spec.style.AnnotationSpec\nimport org.junit.Assert.*\nimport java.util.*\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport java.util.concurrent.TimeUnit\n\n/**\n * Test [Transmitter] from user code(different package)\n */\nclass TransmittableThreadLocal_Transmitter_UserTest : AnnotationSpec() {\n\n    @Test\n    fun test_crr() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(PARENT)\n\n        val capture = Transmitter.capture()\n\n        val future = executorService.submit {\n            ttl.set(CHILD)\n\n            val backup = Transmitter.replay(capture)\n\n            assertEquals(PARENT, ttl.get())\n\n            Transmitter.restore(backup)\n\n            assertEquals(CHILD, ttl.get())\n        }\n\n        assertEquals(PARENT, ttl.get())\n\n        future.get(1, TimeUnit.SECONDS)\n\n        assertEquals(PARENT, ttl.get())\n    }\n\n    @Test\n    fun test_clear_restore() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(PARENT)\n\n        val future = executorService.submit {\n            ttl.set(CHILD)\n\n            val backup = Transmitter.clear()\n\n            assertNull(ttl.get())\n\n            Transmitter.restore(backup)\n\n            assertEquals(CHILD, ttl.get())\n        }\n\n        assertEquals(PARENT, ttl.get())\n\n        future.get(1, TimeUnit.SECONDS)\n\n        assertEquals(PARENT, ttl.get())\n    }\n\n    @Test\n    fun test_runSupplierWithCaptured() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(PARENT)\n\n        val capture = Transmitter.capture()\n\n        val future = executorService.submit {\n            ttl.set(\"child\")\n            Transmitter.runSupplierWithCaptured(capture) {\n                assertEquals(PARENT, ttl.get())\n                ttl.get()\n            }\n        }\n\n        assertEquals(PARENT, ttl.get())\n\n        future.get(1, TimeUnit.SECONDS)\n\n        assertEquals(PARENT, ttl.get())\n    }\n\n    @Test\n    fun test_runSupplierWithClear() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(PARENT)\n\n        val future = executorService.submit {\n            ttl.set(\"child\")\n            Transmitter.runSupplierWithClear {\n                assertNull(ttl.get())\n                ttl.get()\n            }\n        }\n\n        assertEquals(PARENT, ttl.get())\n\n        future.get(1, TimeUnit.SECONDS)\n\n        assertEquals(PARENT, ttl.get())\n    }\n\n    @Test\n    fun test_runCallableWithCaptured() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(PARENT)\n\n        val capture = Transmitter.capture()\n\n        val future = executorService.submit {\n            ttl.set(\"child\")\n            try {\n                Transmitter.runCallableWithCaptured(capture) {\n                    assertEquals(PARENT, ttl.get())\n                    ttl.get()\n                }\n            } catch (e: Exception) {\n                throw RuntimeException(e)\n            }\n        }\n\n        assertEquals(PARENT, ttl.get())\n\n        future.get(1, TimeUnit.SECONDS)\n\n        assertEquals(PARENT, ttl.get())\n    }\n\n    @Test\n    fun test_runCallableWithClear() {\n        val ttl = TransmittableThreadLocal<String>()\n        ttl.set(PARENT)\n\n        val future = executorService.submit {\n            ttl.set(\"child\")\n            try {\n                Transmitter.runCallableWithClear {\n                    assertNull(ttl.get())\n                    ttl.get()\n                }\n            } catch (e: Exception) {\n                throw RuntimeException(e)\n            }\n        }\n\n        assertEquals(PARENT, ttl.get())\n\n        future.get(1, TimeUnit.SECONDS)\n\n        assertEquals(PARENT, ttl.get())\n    }\n\n\n    @AfterAll\n    fun afterAll() {\n        executorService.shutdown()\n        assertTrue(\"Fail to shutdown thread pool\", executorService.awaitTermination(1, TimeUnit.SECONDS))\n    }\n\n    companion object {\n        private val PARENT = \"parent: \" + Date()\n        private val CHILD = \"child: \" + Date()\n\n        private val executorService: ExecutorService = Executors.newFixedThreadPool(3).also { expandThreadPool(it) }\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/user_api_test/ttl/TransmittableThreadLocal_Transmitter_registerTransmittee_UserTest.kt",
    "content": "package com.alibaba.user_api_test.ttl\n\nimport com.alibaba.noTtlAgentRun\nimport com.alibaba.ttl.TransmittableThreadLocal.Transmitter\nimport io.kotest.core.spec.style.AnnotationSpec\nimport io.kotest.core.test.config.TestCaseConfig\nimport io.kotest.matchers.booleans.shouldBeTrue\nimport io.mockk.*\nimport org.apache.commons.lang3.JavaVersion\nimport org.apache.commons.lang3.SystemUtils\n\n/**\n * Test [Transmitter] from user code(different package)\n */\nclass TransmittableThreadLocal_Transmitter_registerTransmittee_UserTest : AnnotationSpec() {\n    @Suppress(\"OVERRIDE_DEPRECATION\")\n    override fun defaultTestCaseConfig(): TestCaseConfig {\n        // If run under Agent and under java 11+, fail to find proxy classes;\n        // so just skipped.\n        //\n        // error info:\n        //   java.lang.NoClassDefFoundError: io/mockk/proxy/jvm/advice/jvm/JvmMockKProxyInterceptor\n        // more info error info see:\n        //   https://github.com/alibaba/transmittable-thread-local/runs/7826806473?check_suite_focus=true\n        if (SystemUtils.isJavaVersionAtMost(JavaVersion.JAVA_1_8)) {\n            return TestCaseConfig(enabled = true)\n        }\n\n        return TestCaseConfig(enabled = noTtlAgentRun())\n    }\n\n    @Test\n    fun test_registerTransmittee_crr() {\n        // ========================================\n        // 0. mocks creation and stubbing\n        // ========================================\n        val transmittee = mockk<Transmitter.Transmittee<List<String>, Set<Int>>>()\n        @Suppress(\"UnusedEquals\", \"ReplaceCallWithBinaryOperator\")\n        excludeRecords {\n            transmittee.equals(any())\n            transmittee.hashCode()\n        }\n\n        every { transmittee.capture() } returns listOf(\"42\", \"43\")\n        every { transmittee.replay(listOf(\"42\", \"43\")) } returns setOf(42, 43)\n        every { transmittee.restore(setOf(42, 43)) } just Runs\n\n        try {\n            // ========================================\n            // 1. mock record(aka. invocation)\n            // ========================================\n            Transmitter.registerTransmittee(transmittee).shouldBeTrue()\n\n            val captured = Transmitter.capture()\n            val backup = Transmitter.replay(captured)\n            Transmitter.restore(backup)\n\n            // ========================================\n            // 2. mock verification\n            // ========================================\n            verifySequence {\n                transmittee.capture()\n                transmittee.replay(any())\n                transmittee.restore(any())\n            }\n            confirmVerified(transmittee)\n        } finally {\n            Transmitter.unregisterTransmittee(transmittee).shouldBeTrue()\n        }\n    }\n\n    @Test\n    fun test_registerTransmittee_clear_restore() {\n        // ========================================\n        // 0. mocks creation and stubbing\n        // ========================================\n        val transmittee = mockk<Transmitter.Transmittee<List<String>, Set<Int>>>()\n        @Suppress(\"UnusedEquals\", \"ReplaceCallWithBinaryOperator\")\n        excludeRecords {\n            transmittee.equals(any())\n            transmittee.hashCode()\n        }\n\n        every { transmittee.clear() } returns setOf(42, 43)\n        every { transmittee.restore(setOf(42, 43)) } just Runs\n\n        try {\n            // ========================================\n            // 1. mock record(aka. invocation)\n            // ========================================\n            Transmitter.registerTransmittee(transmittee).shouldBeTrue()\n\n            val backup = Transmitter.clear()\n            Transmitter.restore(backup)\n\n            // ========================================\n            // 2. mock verification\n            // ========================================\n            verifySequence {\n                transmittee.clear()\n                transmittee.restore(any())\n            }\n            confirmVerified(transmittee)\n        } finally {\n            Transmitter.unregisterTransmittee(transmittee).shouldBeTrue()\n        }\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/user_api_test/ttl/TransmittableThreadLocal_withInit_Null_Test.java",
    "content": "package com.alibaba.user_api_test.ttl;\n\nimport com.alibaba.ttl.TransmittableThreadLocal;\nimport org.junit.Test;\n\nimport java.util.function.Supplier;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\npublic class TransmittableThreadLocal_withInit_Null_Test {\n\n    @Test\n    public void test_null__withInitial() {\n        try {\n            TransmittableThreadLocal.<String>withInitial(null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"supplier is null\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void test_null__withInitialAndCopier_2() {\n        try {\n            TransmittableThreadLocal.<String>withInitialAndCopier(null, null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"supplier is null\", e.getMessage());\n        }\n\n        try {\n            TransmittableThreadLocal.withInitialAndCopier((Supplier<String>) () -> null, null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"ttl copier is null\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void test_null__withInitialAndCopier_3() {\n        try {\n            TransmittableThreadLocal.<String>withInitialAndCopier(null, null, null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"supplier is null\", e.getMessage());\n        }\n\n        try {\n            TransmittableThreadLocal.withInitialAndCopier((Supplier<String>) () -> null, null, null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"ttl copier for child value is null\", e.getMessage());\n        }\n\n        try {\n            TransmittableThreadLocal.withInitialAndCopier((Supplier<String>) () -> null, parentValue -> null, null);\n            fail();\n        } catch (NullPointerException e) {\n            assertEquals(\"ttl copier for copy value is null\", e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/java/com/alibaba/user_api_test/ttl/TransmittableThreadLocal_withInit_Test.kt",
    "content": "package com.alibaba.user_api_test.ttl\n\nimport com.alibaba.expandThreadPool\nimport com.alibaba.ttl.TransmittableThreadLocal\nimport com.alibaba.ttl.threadpool.TtlExecutors\nimport io.kotest.core.spec.style.AnnotationSpec\nimport org.junit.Assert.*\nimport java.util.concurrent.ExecutorService\nimport java.util.concurrent.Executors\nimport java.util.concurrent.TimeUnit\nimport java.util.concurrent.atomic.AtomicInteger\nimport kotlin.concurrent.thread\n\nclass TransmittableThreadLocal_withInit_Test : AnnotationSpec() {\n\n    @Test\n    fun test_withInit() {\n        val ttl: TransmittableThreadLocal<Int> = TransmittableThreadLocal.withInitial { 42 }\n\n        assertNotNull(ttl)\n        assertEquals(42, ttl.get())\n\n        val atomicInteger = AtomicInteger(-1)\n        thread {\n            atomicInteger.set(ttl.get())\n        }.join()\n        assertEquals(42, atomicInteger.get())\n\n        atomicInteger.set(-1)\n        executorService.submit {\n            atomicInteger.set(ttl.get())\n        }.get()\n        assertEquals(42, atomicInteger.get())\n    }\n\n    @Test\n    fun test_withInitialAndCopier_2() {\n        val ttl = TransmittableThreadLocal.withInitialAndCopier(\n            { 42 },\n            { it + 100 },\n        )\n        assertNotNull(ttl)\n        assertEquals(42, ttl.get())\n\n        val atomicInteger = AtomicInteger(-1)\n        thread {\n            atomicInteger.set(ttl.get())\n        }.join()\n        assertEquals(142, atomicInteger.get())\n\n        atomicInteger.set(-1)\n        executorService.submit {\n            atomicInteger.set(ttl.get())\n        }.get()\n        assertEquals(142, atomicInteger.get())\n    }\n\n    @Test\n    fun test_withInitialAndCopier_3() {\n        val ttl = TransmittableThreadLocal.withInitialAndCopier(\n            { 42 },\n            { it + 100 },\n            { it + 1000 },\n        )\n        assertNotNull(ttl)\n        assertEquals(42, ttl.get())\n\n        val atomicInteger = AtomicInteger(-1)\n        thread {\n            atomicInteger.set(ttl.get())\n        }.join()\n        assertEquals(142, atomicInteger.get())\n\n        atomicInteger.set(-1)\n        executorService.submit {\n            atomicInteger.set(ttl.get())\n        }.get()\n        assertEquals(1042, atomicInteger.get())\n    }\n\n    @AfterAll\n    fun afterClass() {\n        executorService.shutdown()\n        assertTrue(\n            \"Fail to shutdown thread pool\",\n            executorService.awaitTermination(1, TimeUnit.SECONDS)\n        )\n    }\n\n    companion object {\n        private val executorService: ExecutorService = Executors.newFixedThreadPool(3).let {\n            expandThreadPool(it)\n            TtlExecutors.getTtlExecutorService(it)!!\n        }\n    }\n}\n"
  },
  {
    "path": "ttl2-compatible/src/test/resources/io/mockk/settings.properties",
    "content": "stackTracesAlignment=left\n"
  },
  {
    "path": "ttl2-compatible/src/test/resources/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">\n<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" debug=\"false\">\n\t<appender name=\"CONSOLE\" class=\"org.apache.log4j.ConsoleAppender\">\n\t\t<layout class=\"org.apache.log4j.PatternLayout\">\n\t\t\t<param name=\"ConversionPattern\" value=\"%d %t %5p %c{2} - %m%n\" />\n\t\t</layout>\n\t</appender>\n\t<root>\n\t\t<level value=\"DEBUG\" />\n\t\t<appender-ref ref=\"CONSOLE\" />\n\t</root>\n</log4j:configuration>\n"
  },
  {
    "path": "ttl2-compatible/src/test/resources/test_extension/foo.txt",
    "content": "# comments\n\nhello.World # comments\n\nspaceInside space\ntabInside\ttab\n\n\thello.tabBefore\nhello.tabAfter\n  hello.spaceBefore\nhello.spaceAfter\n\nhello.!IllegalName\n"
  }
]